Autofac for AutoMapper

我一直在作的事情。NET 开发已经有一段时间了。有时人们问我,为何我仍然以为它有趣。答案很简单: 我是超级 d.r.y。若是你不熟悉这个术语,你应该查一下,但它基本上意味着你应该老是尝试应用那些能够,或者更好的,已经被重复使用的解决方案。不要重复本身的话。web

一个好的实践是用已经存在的框架自动化全部可能的事情。解析因为使用依赖注入而产生的对象图是一个应该自动化的常见任务。个人选择是AutoMapper 。NET 框架开发。固然。基于 NET 核心的框架有他们本身的:)微信

在 web 应用程序中常常出现的另外一个常见问题是将视图模型或 dto 转换为域对象,反之亦然。一样,为了尽量地自动化这个过程,我一般使用 AutoMapper。app

问题是AutoMapper 和Autofac配合很差。Autofac 项目在 Github 上很是活跃,它们支持不少不一样的框架,可是不支持 AutoMapper。虽然 AutoMapper 也支持许多不一样的框架,甚至 ASP.NET Core MVC 的 DI 框架,可是它对于普通的旧 ASP.NET MVC 或 Web API 2没有任何支持。这真是太惋惜了:)框架

因此看了下 Automapper ASP.NET Core MVC 集成的源代码,以得到灵感。这种配置添加了 AutoMapper 及其服务,所以您能够轻松地将 IMapper 注入到您的控制器中。注册名单以下:ide

  • As a singleton for the MapperConfiguration
  • As a transient instance for IMapper
  • ITypeConverter instances as transient
  • IValueConverter instances as transient IValueConverter
  • IValueResolver instances as transient
  • IMemberValueResolver instances as transient IMemberValueResolver
  • IMappingAction instances as transient

我猜有不少缘由能够解释为何这些是不一样服务的注册,因此我决定为 Autofac 也实现一些相似的东西。我基本上建立了一个新的 Autofac 模块,复制了代码,删除了一些我认为没必要要的东西,稍微修改了一下,使用了 Autofac 方法,就这样:svg

public class AutoMapperModule : Autofac.Module
{

  private readonly IEnumerable<Assembly> assembliesToScan;
  public AutoMapperModule(IEnumerable<Assembly> assembliesToScan)
  {
    this.assembliesToScan = assembliesToScan;
  }

  public AutoMapperModule(params Assembly[] assembliesToScan) : this((IEnumerable<Assembly>)assembliesToScan) { }
  
  protected override void Load(ContainerBuilder builder)
  {
    base.Load(builder);          
    var assembliesToScan = this.assembliesToScan as Assembly[] ?? this.assembliesToScan.ToArray();

    var allTypes = assembliesToScan
                  .Where(a => !a.IsDynamic && a.GetName().Name != nameof(AutoMapper))
                  .Distinct() // avoid AutoMapper.DuplicateTypeMapConfigurationException
                  .SelectMany(a => a.DefinedTypes)
                  .ToArray();

    var openTypes = new[] {
                            typeof(IValueResolver<,,>),
                            typeof(IMemberValueResolver<,,,>),
                            typeof(ITypeConverter<,>),
                            typeof(IValueConverter<,>),
                            typeof(IMappingAction<,>)
            };
   
   foreach (var type in openTypes.SelectMany(openType => 
    allTypes.Where(t => t.IsClass && !t.IsAbstract && ImplementsGenericInterface(t.AsType(), openType))))
   {
     builder.RegisterType(type.AsType()).InstancePerDependency();
   }

    builder.Register<IConfigurationProvider>(ctx => new MapperConfiguration(cfg => cfg.AddMaps(assembliesToScan))).SingleInstance();
   
    builder.Register<IMapper>(ctx => new Mapper(ctx.Resolve<IConfigurationProvider>(), ctx.Resolve)).InstancePerDependency();
 }
 
 private static bool ImplementsGenericInterface(Type type, Type interfaceType)
           => IsGenericType(type, interfaceType) || type.GetTypeInfo().ImplementedInterfaces.Any(@interface => IsGenericType(@interface, interfaceType));

  private static bool IsGenericType(Type type, Type genericType)
            => type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == genericType;
}

如今,您能够简单地将这个模块添加到 Autofac ContainerBuilder 中。对于 ASP.NET Web API,若是您在 Web API 项目中定义映射配置文件,则能够将 typeof (Startup)传递给模块 constuctor (并且因为 dto 只用于与客户机通讯,那么它们还能在哪里呢?)而后可使用构造函数注入来得到 IMapper 实例。函数

后记

本人不是大佬,只是道路先行者,在落河后,向后来的人大喊一声,这里有坑,不要过来啊!网站

纵然如此,依旧有人重复着落河,重复着呐喊······ui

我的博客网站 Blogthis

技术交流Q群: 1012481075 群内有各类流行书籍资料

文章后续会在公众号更新,微信搜索 OneByOneDotNet 便可关注。

你的一分鼓励,个人十分动力,点赞免费,感恩回馈。喜欢就点赞评论吧,双击6666~

相关文章
相关标签/搜索