2012-02-03 66 views
14

我有一個ViewModel需要一些模型數據並略微改變它。如何處理AutoMapper中的自定義屬性

我這樣做的方式「起作用」,因爲我只是將DomainModel傳遞給ViewModel的構造函數,但由於我在一些一對一ViewModels上使用AutoMapper,我以爲我會嘗試並學習如何在所有ViewModel中進行映射。

下面是一個ViewModel的例子,它做了一些額外的工作。

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; 
    } 

} 

這裏就是我目前使用上述視圖模型

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(); 
    } 

} 

如何使用(或我應該使用)AutoMapper我的DomainModel映射到我的視圖模型,而這樣做,你在上面看到的定製處理?

回答

38

在創建Map的automapper上,您可以爲目標類型的特定成員指定其他進程。

那麼,你的默認的地圖將

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

有一個流暢的語法來定義更爲複雜的映射:

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

這裏ForMember需要兩個參數,第定義屬性,您正在映射到。第二個提供了一種定義映射的方法。舉個例子,我已經刪除並顯示了一個簡單的映射。

如果您需要更困難的映射(例如CurrentUser映射),您可以創建一個實現IResolver接口的類,將映射邏輯合併到新的類中,然後將其添加到映射中。

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

當Mapper來做映射時,它會調用你的自定義解析器。

一旦您發現.ForMember方法的所有其他類型的插槽到位的語法。

13

自定義映射可以在global.ascx(在啓動時)由以下代碼來定義:

 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)); 

可以經由BeforeMap做一些初始化()方法。但是您可能需要在視圖模型中進行一些更改。