如何在AutoMapper中处理自定义属性

问题描述 投票:0回答:4

我有一个 ViewModel,它获取一些模型数据并稍微改变它。

我这样做的方式“有效”,因为我只是将

DomainModel
传递给
ViewModel
的构造函数,但由于我在一些一对一的 ViewModel 上使用 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;
    }

}

这是我目前使用上述 ViewModel 的方式

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 映射到 ViewModel?

c# asp.net-mvc-3 viewmodel automapper
4个回答
65
投票

在创建映射的自动映射器上,您可以为目标类型的特定成员指定其他进程。

那么你的默认地图在哪里

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 方法的语法,其他所有内容就都到位了。


20
投票

可以通过以下代码在 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()方法进行一些初始化。但您可能需要在视图模型中进行一些更改。


3
投票

我认为语法在 2019 年(ASP.NET Core 2.2)略有变化,现在使用 MapperConfiguration 处理此方法,并且静态方法不再可用。

但是我同意@KJSR,这篇文章仍然非常有用:-)

 private Mapper UserMapper= new Mapper(new MapperConfiguration(cfg => (cfg.CreateMap<Domain.User, UsersDetailsViewModel>())
            .ForMember(x=>x.Email, y=>y.MapFrom(z=>z.Email))
            .ForMember(x => x.UserName , y => y.MapFrom(user => (user.UserName != null) ? user.UserName : "User" + user.ID.ToString))));

0
投票

创建地图() .ForMember(x => x.EndDate, a => a.MapFrom(u => Convert.ToDateTime(u.EndDate).ToString(ConstantValues.DDMMYYYY)));

© www.soinside.com 2019 - 2024. All rights reserved.