我在ASP中使用AutoMapper。NET MVC应用程序。有人告诉我,我应该把自动取款机移走。在其他地方创建地图,因为他们有很多开销。我不太确定如何设计我的应用程序,把这些调用放在一个地方。

我有一个网络层,服务层和数据层。每个项目都有自己的特色。我用Ninject来DI所有东西。我将在web层和服务层使用AutoMapper。

那么,你为AutoMapper的CreateMap设置了什么?你把它放在哪里?你怎么称呼它?


当前回答

你可以把它放在任何地方,只要你的web项目引用它所在的程序集。在你的情况下,我会把它放在服务层,因为它将被web层和服务层访问,之后如果你决定做一个控制台应用程序或你正在做一个单元测试项目,映射配置也将从这些项目中可用。

在你的全局中。Asax,然后你将调用方法,设置你的所有地图。见下文:

文件AutoMapperBootStrapper.cs

public static class AutoMapperBootStrapper
{
     public static void BootStrap()
     {  
         AutoMapper.CreateMap<Object1, Object2>();
         // So on...


     }
}

全球。Asax应用程序启动

就叫

AutoMapperBootStrapper.BootStrap();

现在有些人会反对这种方法违反了一些坚实的原则,他们有有效的理由。这是供阅读的。

在Bootstrapper中配置Automapper违反了开闭原则?

其他回答

对于那些坚持以下原则的人:

使用ioc容器 我可不想因为这个破门而入 不喜欢单一的配置文件

我在配置文件和利用ioc容器之间做了一个组合:

IoC配置:

public class Automapper : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());

        container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
        {
            Profile[] profiles = k.ResolveAll<Profile>();

            Mapper.Initialize(cfg =>
            {
                foreach (var profile in profiles)
                {
                    cfg.AddProfile(profile);
                }
            });

            profiles.ForEach(k.ReleaseComponent);

            return Mapper.Engine;
        }));
    }
}

配置的例子:

public class TagStatusViewModelMappings : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
    }
}

使用的例子:

public class TagStatusController : ApiController
{
    private readonly IFooService _service;
    private readonly IMappingEngine _mapper;

    public TagStatusController(IFooService service, IMappingEngine mapper)
    {
        _service = service;
        _mapper = mapper;
    }

    [Route("")]
    public HttpResponseMessage Get()
    {
        var response = _service.GetTagStatus();

        return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response)); 
    }
}

代价是必须通过IMappingEngine接口引用Mapper,而不是静态Mapper,但这是我可以接受的约定。

将所有映射逻辑放在一个位置对我来说不是一个好的实践。因为映射类非常大,很难维护。

我建议把映射的东西和ViewModel类放在同一个cs文件中。您可以按照这个约定轻松地导航到您想要的映射定义。此外,在创建映射类时,您可以更快地引用ViewModel属性,因为它们在同一个文件中。

所以你的视图模型类看起来像这样:

public class UserViewModel
{
    public ObjectId Id { get; set; }

    public string Firstname { get; set; }

    public string Lastname { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }
}

public class UserViewModelMapping : IBootStrapper // Whatever
{
    public void Start()
    {
        Mapper.CreateMap<User, UserViewModel>();
    }
}

对于使用AutoMapper新版本(5.x)的vb.net程序员。

Global.asax.vb:

Public Class MvcApplication
    Inherits System.Web.HttpApplication

    Protected Sub Application_Start()
        AutoMapperConfiguration.Configure()
    End Sub
End Class

AutoMapperConfiguration:

Imports AutoMapper

Module AutoMapperConfiguration
    Public MapperConfiguration As IMapper
    Public Sub Configure()
        Dim config = New MapperConfiguration(
            Sub(cfg)
                cfg.AddProfile(New UserProfile())
                cfg.AddProfile(New PostProfile())
            End Sub)
        MapperConfiguration = config.CreateMapper()
    End Sub
End Module

配置文件:

Public Class UserProfile
    Inherits AutoMapper.Profile
    Protected Overrides Sub Configure()
        Me.CreateMap(Of User, UserViewModel)()
    End Sub
End Class

映射:

Dim ViewUser = MapperConfiguration.Map(Of UserViewModel)(User)

在新版本的AutoMapper中,使用静态方法Mapper.Map()已弃用。因此,您可以将MapperConfiguration作为静态属性添加到MvcApplication (Global.asax.cs),并使用它来创建Mapper的实例。

App_Start

public class MapperConfig
{
    public static MapperConfiguration MapperConfiguration()
    {
        return new MapperConfiguration(_ =>
        {
            _.AddProfile(new FileProfile());
            _.AddProfile(new ChartProfile());
        });
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    internal static MapperConfiguration MapperConfiguration { get; private set; }

    protected void Application_Start()
    {
        MapperConfiguration = MapperConfig.MapperConfiguration();
        ...
    }
}

BaseController.cs

    public class BaseController : Controller
    {
        //
        // GET: /Base/
        private IMapper _mapper = null;
        protected IMapper Mapper
        {
            get
            {
                if (_mapper == null) _mapper = MvcApplication.MapperConfiguration.CreateMapper();
                return _mapper;
            }
        }
    }

https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API

没关系,只要它是一个静态类。这都是惯例。

我们的约定是,每个“层”(web、服务、数据)都有一个名为AutoMapperXConfiguration.cs的文件,带有一个名为Configure()的方法,其中X是层。

然后Configure()方法为每个区域调用私有方法。

下面是我们web层配置的一个例子:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      ConfigureUserMapping();
      ConfigurePostMapping();
   }

   private static void ConfigureUserMapping()
   {
      Mapper.CreateMap<User,UserViewModel>();
   } 

   // ... etc
}

我们为每个“聚合”(User, Post)创建了一个方法,这样事情就被很好地分开了。

然后是Global.asax:

AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc

它有点像“文字界面”——不能强制执行,但你希望它,所以你可以在必要时编码(和重构)。

编辑:

我只是想提一下我现在使用AutoMapper配置文件,所以上面的例子变成:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      Mapper.Initialize(cfg =>
      {
        cfg.AddProfile(new UserProfile());
        cfg.AddProfile(new PostProfile());
      });
   }
}

public class UserProfile : Profile
{
    protected override void Configure()
    {
         Mapper.CreateMap<User,UserViewModel>();
    }
}

更干净/更坚固。