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

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

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


当前回答

除了最好的答案,一个好方法是使用Autofac IoC库添加一些自动化。使用这种方法,您只需定义您的概要文件,而不管初始化。

   public static class MapperConfig
    {
        internal static void Configure()
        {

            var myAssembly = Assembly.GetExecutingAssembly();

            var builder = new ContainerBuilder();

            builder.RegisterAssemblyTypes(myAssembly)
                .Where(t => t.IsSubclassOf(typeof(Profile))).As<Profile>();

            var container = builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                var profiles = container.Resolve<IEnumerable<Profile>>();

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

            }

        }
    }

并在Application_Start方法中调用这一行:

MapperConfig.Configure();

上面的代码找到所有Profile子类并自动初始化它们。

其他回答

对于使用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)

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

我建议把映射的东西和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>();
    }
}

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

我们的约定是,每个“层”(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>();
    }
}

更干净/更坚固。

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

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

文件AutoMapperBootStrapper.cs

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


     }
}

全球。Asax应用程序启动

就叫

AutoMapperBootStrapper.BootStrap();

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

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

以上所有解决方案都提供了一个静态方法来调用(从app_start或任何位置),它应该调用其他方法来配置映射配置的部分。但是,如果您有一个模块化的应用程序,该模块可能在任何时候插入和退出应用程序,这些解决方案是行不通的。我建议使用WebActivator库,可以注册一些方法运行在app_pre_start和app_post_start的任何地方:

// in MyModule1.dll
public class InitMapInModule1 {
    static void Init() {
        Mapper.CreateMap<User, UserViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule1), "Init")]

// in MyModule2.dll
public class InitMapInModule2 {
    static void Init() {
        Mapper.CreateMap<Blog, BlogViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]

// in MyModule3.dll
public class InitMapInModule3 {
    static void Init() {
        Mapper.CreateMap<Comment, CommentViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]

// and in other libraries...

你可以通过NuGet安装WebActivator。