Domanda Come gestire le proprietà personalizzate in AutoMapper


Ho un ViewModel che prende alcuni dati del modello e lo modifica leggermente.

Il modo in cui lo sto facendo "funziona" da quando ho appena passato il DomainModel al costruttore per il ViewModel, ma dal momento che sto usando AutoMapper su alcuni dei miei ViewModels one-to-one, ho pensato di provare a imparare come eseguire la mappatura su tutti i ViewModels.

Ecco un esempio di un ViewModel che fa un piccolo extra.

public class UsersDetailsViewModel
{
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Website { get; set; }
    public int ID { get; set; }
    public List<OpenID> OpenIds { get; set; }
    public string UserAge { get; set; }
    public string About { get; set; }
    public string Slug { get; set; }
    public System.DateTime LastSeen { get; set; }
    public string Region { get; set; }
    public string MemberSince { get; set; }
    public string Reputation { get; set; }
    public bool IsUserMatch { get; set; }

    private readonly MarkdownDeep.Markdown _markdown;


    public UsersDetailsViewModel(Domain.User user)
    {
        AuthUserData currentuser = AuthenticationHelper.RetrieveAuthUser;
        _markdown.NoFollowLinks = true;
        _markdown.SafeMode = true;
        _markdown.ExtraMode = false;
        _markdown.MarkdownInHtml = true;

        // We want to ensure that the user has a username, even if they
        // haven't set one yet. What this does is check to see if the
        // user.UserName field is blank, and if it is, it will set the
        // username to "UserNNNN" where NNNN is the user ID number.
        _UserName = (user.UserName != null) ? user.UserName : "User" + user.ID.ToString;

        // Nothing fancy going on here, we're just re-passing the object from
        // the database to the View. No data manipulation!
        _Email = user.Email;
        _Website = user.WebSite;
        _ID = user.ID;

        // Get's a list of all of the user's OpenID's
        _OpenIds = user.OpenIDs.ToList;

        // Converts the users birthdate to an age representation
        _UserAge = user.BirthDate.ToAge;
        //IE: 29

        // Because some people can be real ass holes and try to submit bad
        // data (scripts and shitè) we have to modify the "About" content in
        // order to sanitize it.  At the same time, we transform the Markdown
        // into valid HTML. The raw input is stored without sanitization in
        // the database.  this could mean Javascript injection, etc, so the
        // output ALWAYS needs to be sanitized.

        // This method below was used in conjunction with MarkDownSharp
        // _About = Trim(Utilities.HtmlSanitizer.Sanitize(Markdown.Transform(user.About)))
        _About = _markdown.Transform(user.About);

        // Removes spaces from Usernames in order to properly display the
        // username in the address bar
        _Slug = Strings.Replace(user.UserName, " ", "-");

        // Returns a boolean result if the current logged in user matches the
        // details view of tBhe user in question.  This is done so that we can
        // show the edit button to logged in users.
        _IsUserMatch = (currentuser.ID == user.ID);


        // Grabs the users registration data and formats it to a <time> tag
        // for use with the timeago jQuery plugin
        _MemberSince = user.MemberSince;

        // Grabs the users last activity and formats it to a <time> tag
        // for use with the timeago jQuery plugin
        _LastSeen = user.ActivityLogs.Reverse.FirstOrDefault.ActivityDate;

        // Formats the users reputation to a comma Deliminated number 
        //    IE: 19,000 or 123k
        _Reputation = user.Reputation.ToShortHandNumber;


        // Get the name of the users Default Region.
        _Region = user.Region.Name.FirstOrDefault;
    }

}

Ed ecco come attualmente utilizzo ViewModel sopra

public ActionResult Details(int id)
{
    User user = _userService.GetUserByID(id);

    if (user != null) {
        Domain.ViewModels.UsersDetailsViewModel userviewmodel = new Domain.ViewModels.UsersDetailsViewModel(user);
        return View(userviewmodel);
    } else {
        // Because of RESTful URL's, some people will want to "hunt around"
        // for other users by entering numbers into the address.  We need to
        // gracefully redirect them to a not found page if the user doesn't
        // exist.
        throw new ResourceNotFoundException();
    }

}

Come posso utilizzare (o dovrei usare) AutoMapper per mappare il mio DomainModel al mio ViewModel mentre eseguo l'elaborazione personalizzata che vedi sopra?


17
2018-02-03 16:49


origine


risposte:


Nel automapper in cui si crea la mappa è possibile specificare processi aggiuntivi per membri specifici del tipo di destinazione.

Quindi dove sarebbe la tua mappa di default

Mapper.Map<Domain.User, UsersDetailsViewModel>();

c'è una sintassi fluente per definire i mapping più complicati:

Mapper.Map<Domain.User, UsersDetailsViewModel>()
      .ForMember(vm=>vm.UserName, m=>m.MapFrom(u=>(u.UserName != null) 
                                               ? u.UserName 
                                               : "User" + u.ID.ToString()));

Qui il ForMember prende due Argomenti, il primo definisce la proprietà a cui stai mappando. Il secondo fornisce un mezzo per definire la mappatura. Per un esempio sono saltato fuori e ho mostrato una delle mappature facili.

Se è necessaria una mappatura più complessa, (come la mappatura CurrentUser) è possibile creare una classe che implementa l'interfaccia IResolver, incorporare la logica di mappatura in quei nuovi clase e quindi aggiungerla alla mappatura.

Mapper.Map<Domain.User, UsersDetailsViewModel>()
  .ForMember(vm=>vm.IsUserMatch, m=>m.ResolveUsing<MatchingUserResolver>()));

quando Mapper arriverà a fare il mapping invocherà il tuo resolver personalizzato.

Una volta che scopri la sintassi del metodo .ForMember, tutto il genere di slot in posizione.


41
2018-02-03 20:48



La mappatura personalizzata può essere definita in global.ascx (all'avvio) seguendo i seguenti codici:

      AutoMapper.Mapper.CreateMap<Domain.User, UsersDetailsViewModel>()
          .ForMember(o => o.Email, b => b.MapFrom(z => z.Email))
          .ForMember(o => o.UserName , b => b.MapFrom(user => (user.UserName != null) ? user.UserName : "User" + user.ID.ToString));

è possibile eseguire l'inizializzazione tramite il metodo BeforeMap (). Ma potrebbe essere necessario apportare alcune modifiche al tuo modello di visualizzazione.


14
2018-02-03 20:49