Contents

ASP.NET Core 3.1 使用 Autofac 與註冊其他分層

ASP.NET Core 3.1 使用 Autofac 與註冊其他分層

步入ASP.NET Core 一定會遇到控制反轉(IoC)和相依性注入(DI)議題,ASP.NET Core有預設的DI Container 就是使用AddTransientAddScopedAddSingleton,但若覺得內建的太簡易,可選擇第三方DI Container,最知名的選擇應該就是Autofac,這邊簡單介紹一下Autofac基本導入,與幾種註冊其他分層方式

環境

  • Nuget > Autofac.Extensions.DependencyInjection

架構

/static/使用Autofac與註冊其他分層_ecae0588632f467183868512aa95ac03/2021-01-19_14-37-03.png

ASP.NET Core 3.1 預設 DI 用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IProductRepository, ProductRepository>();
    services.AddScoped<IProductService, ProductService>();
    services.AddScoped<IOrderRepository, OrderRepository>();
    services.AddScoped<IOrderService, OrderService>();

    services.AddScoped<IStatistics, Sales>();

    services.AddControllersWithViews();
}

ASP.NET Core 3.1 導入 Autofac

  1. 安裝 Autofac.Extensions.DependencyInjection

    /static/使用Autofac與註冊其他分層_ecae0588632f467183868512aa95ac03/2021-01-19_14-47-11.png
  2. Program.cs 加入服務

    1
    2
    3
    4
    5
    6
    7
    
    public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
              .UseServiceProviderFactory(new AutofacServiceProviderFactory()) // 這行
              .ConfigureWebHostDefaults(webBuilder =>
              {
                  webBuilder.UseStartup<Startup>();
              });
    
  3. Startup.cs 加入公開的 ConfigureContainer() 方法,將要註冊的服務寫在裡面就完成了

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }
    
    public void ConfigureContainer(ContainerBuilder builder)
    {
        // SingleInstance 相當於 AddSingleton
        // InstancePerLifetimeScope 相當於 AddScoped
        // InstancePerDependency 相當於 AddTransient
        builder.RegisterType<ProductRepository>().As<IProductRepository>().InstancePerLifetimeScope();
        builder.RegisterType<ProductService>().As<IProductService>().InstancePerLifetimeScope();
        builder.RegisterType<OrderRepository>().As<IOrderRepository>().InstancePerLifetimeScope();
        builder.RegisterType<OrderService>().As<IOrderService>().InstancePerLifetimeScope();
    
        builder.RegisterType<Sales>().As<IStatistics>().InstancePerLifetimeScope();
    }
    

大量註冊

以上就是Autofac基本設置,接下來就是各種花式註冊,細節請自行參考 官方文件 ,因為用法很多,這邊純紀錄幾個自己用過的情況

  1. 直接註冊整個專案 或 註冊大量組件

    使用 autofac,如果還一個一個註冊,那其實跟使用內建的沒有兩樣,通常同性質的如Repository層、Service層,結尾都會取相似名稱,這時可以大量註冊,這是我最常用的方法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    public void ConfigureContainer(ContainerBuilder builder)
    {
        // 註冊整個專案
        var assemblysRepository = Assembly.Load("DataLayer");
        builder.RegisterAssemblyTypes(assemblysRepository)
                  .AsImplementedInterfaces()
                  .InstancePerLifetimeScope();
    
        var assemblysServices = Assembly.Load("ServiceLayer");
        builder.RegisterAssemblyTypes(assemblysServices)
                  .AsImplementedInterfaces()
                  .InstancePerLifetimeScope();
    
        // 專案內註冊大量相同結尾的檔案
        //var assemblysRepository = Assembly.Load("DataLayer");
        //builder.RegisterAssemblyTypes(assemblysRepository)
        //       .Where(t => t.Name.EndsWith("Repository"))
        //       .AsImplementedInterfaces()
        //       .InstancePerLifetimeScope();
    
        // 實作與介面不同專案
        //Assembly Repository = Assembly.Load("Repository");
        //Assembly IRepository = Assembly.Load("IRepository");
        //builder.RegisterAssemblyTypes(Repository, IRepository)
        //    .Where(t => t.Name.EndsWith("Repository"))
        //    .AsImplementedInterfaces()
        //    .InstancePerLifetimeScope();
    }
    
  2. 將實作的控制交還各層

    ServiceLayer、DataLayer 安裝 Aufofac ,新增一個類別繼承 Autofac.Module 類別,並且複寫 Autofac.Module.Load 虛擬方法,範例如下

    /static/使用Autofac與註冊其他分層_ecae0588632f467183868512aa95ac03/2021-01-19_18-17-15.png
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    public class ServiceModules : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            var dataAccess = Assembly.GetExecutingAssembly();
    
            builder.RegisterAssemblyTypes(dataAccess)
                .Where(c => c.Name.EndsWith("Service"))
                .AsImplementedInterfaces();
    
            // 讀取組件也可以這麼寫
            //builder.RegisterAssemblyTypes(
            //    GetType().GetTypeInfo().Assembly)
            //    .Where(c => c.Name.EndsWith("Service"))
            //    .AsImplementedInterfaces();
    
            // 指定實作類別
            builder.RegisterType<Sales>().As<IStatistics>().AsImplementedInterfaces();
        }
    }
    

    然後 ConfigureContainer 註冊這個類別

    1
    2
    3
    4
    
    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterModule(new ServiceModules());
    }
    

    好處是可以將實作類別控制權交由各層自行處理,壞處就是各層會增加了對 autofac 的依賴。

  3. 註冊DLL檔

    註冊DLL檔,使用方法和上述是一樣的,先採用專案參考匯入要使用的服務,再設定即可

    /static/使用Autofac與註冊其他分層_ecae0588632f467183868512aa95ac03/2021-01-20_10-05-34.png /static/使用Autofac與註冊其他分層_ecae0588632f467183868512aa95ac03/2021-01-20_10-09-52.png
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<ClassA>().As<IShowClass>().InstancePerLifetimeScope();
    
        // 註冊整個dll
        //var assemblysRepository = Assembly.Load("ClassLibrary1");
        //builder.RegisterAssemblyTypes(assemblysRepository)
        //          .AsImplementedInterfaces()
        //          .InstancePerLifetimeScope();
    }
    

參考

Autofac 官方文件

https://autofac.org/