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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9132251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 06:06:32  来源:igfitidea点击:

How to handle custom Properties in AutoMapper

c#asp.net-mvc-3viewmodelautomapper

提问by Chase Florell

I've got a ViewModel that takes some Model data and slightly alters it.

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

The way I'm doing it "works" since I just pass the DomainModelto the constructor for the ViewModel, but since I'm using AutoMapper on some of my one-to-one ViewModels, I thought I'd try and learn how to do the mapping across all ViewModels.

我这样做的方式“有效”,因为我只是将 传递DomainModel给 的构造函数ViewModel,但是由于我在一些一对一的 ViewModel 上使用 AutoMapper,我想我会尝试学习如何做跨所有 ViewModel 的映射。

Here's an example of a ViewModel that does a little extra.

这是一个 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;
    }

}

And here's how I currently utilize the above ViewModel

这是我目前如何使用上述 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();
    }

}

How can I use (or should I use) AutoMapper to map my DomainModel to my ViewModel while doing the custom processing you see above?

在执行上面看到的自定义处理时,我如何使用(或应该使用)AutoMapper 将我的 DomainModel 映射到我的 ViewModel?

采纳答案by Bobbles

On automapper where you create the Map you can specify additional processes for specific members of the destination type.

在创建 Map 的 automapper 上,您可以为目标类型的特定成员指定其他进程。

So where your default map would be

所以你的默认地图会在哪里

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

there is a fluent syntax to define the more complicated mappings:

有一个流畅的语法来定义更复杂的映射:

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

Here the ForMember takes two Arguments the first defines the property that you are mapping to. The second provides a means of defining the mapping. For an example I have copped out and shown one of the easy mappings.

这里 ForMember 接受两个 Arguments,第一个定义您要映射到的属性。第二个提供了定义映射的方法。举个例子,我已经删掉并展示了一个简单的映射。

If you require a more difficult mapping, (such as your CurrentUser mapping) you can create a class that implements the IResolver interface, incorporate your mapping logic in that new clases and then add that into the mapping.

如果您需要更困难的映射(例如您的 CurrentUser 映射),您可以创建一个实现 IResolver 接口的类,将您的映射逻辑合并到该新类中,然后将其添加到映射中。

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

when Mapper comes to do the mapping it will invoke your custom resolver.

当 Mapper 进行映射时,它将调用您的自定义解析器。

Once you discover the syntax of the .ForMember method everything else kind of slots into place.

一旦你发现了 .ForMember 方法的语法,其他所有类型的插槽都到位了。

回答by Mahmoud Moravej

Custom mapping can be defined in global.ascx (at startup) by following codes :

自定义映射可以通过以下代码在 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));

you can do some initialization via BeforeMap () method. But you may need to do some changes in your viewmodel.

您可以通过 BeforeMap() 方法进行一些初始化。但是您可能需要对视图模型进行一些更改。

回答by XavierAM

I think the syntax has slightly changed in 2019 (ASP.NET Core 2.2), this method is now handled with the MapperConfiguration and the static methods are no more available.

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

But I agree with @KJSR, this post is still really useful :-)

但我同意@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))));