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~

相關文章
相關標籤/搜索