如何使用 Microsoft.Extensions.DependencyInjection for Autofac

微軟提供的 DI Container (Microsoft.Extensions.DependencyInjection ),實作了 Microsoft.Extensions.DependencyInjection.Abstractions 抽象,讓我們也可很輕易的換成我們習慣的 DI Container,比如說,內建的 Microsoft.Extensions.DependencyInjection 沒有提供掃描 Assembly 的自動註冊,這時,在應用程式的進入點換成其它的 DI Container,比如 Autofac,就可以使用自動註冊。

只有增加使用 Autofac DI Container 的註冊,其餘的不用動,像是物件的依賴關係,取出物件方式。

對 MS DI 還不熟的,可以參考以下連結 https://www.dotblogs.com.tw/yc421206/2020/10/29/standard_di_container_for_microsoft_extensions_dependencyInjection

 

開發環境

  • VS IDE 2019
  • ASP.NET Web API 2 & .NET Framework 4.8
  • ASP.NET Core 3.1
  • Autofac.Extensions.DependencyInjection 7.1.0

ASP.NET Web API 2 - Framework 4.8

新增一個 ASP.NET Web Application、.NET Framework 4.8 並安裝以下套件

Install-Package Autofac.Extensions.DependencyInjection

 

關鍵步驟

  • 建立一個 Autofac ContainerBuilder 實例
  • 調用 builder.Populate(services) 方法
  • 使用 Autofac 註冊
/// <summary>
///     使用 Autofac 註冊
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static ContainerBuilder ConfigureContainerBuilder(IServiceCollection services)
{
    var builder = new ContainerBuilder();
    builder.Populate(services);

    var assembly = Assembly.GetExecutingAssembly();
    builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();

    return builder;
}

 

  • 原本使用 services.BuildServiceProvider() ,改用 AutofacServiceProvider 實例,餵給 DefaultDependencyResolver
public static void Register(HttpConfiguration config)
{
    var services = ConfigureServices();
    var builder  = ConfigureContainerBuilder(services);
    var provider = new AutofacServiceProvider(builder.Build());

    //var provider = services.BuildServiceProvider();

    var resolver = new DefaultDependencyResolver(provider);
    config.DependencyResolver = resolver;
}

 

完整代碼如下:

public class DefaultDependencyResolver : IDependencyResolver
{
    protected IServiceProvider ServiceProvider { get; set; }

    public DefaultDependencyResolver(IServiceProvider serviceProvider)
    {
        this.ServiceProvider = serviceProvider;
    }

    public object GetService(Type serviceType)
    {
        return this.ServiceProvider.GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.ServiceProvider.GetServices(serviceType);
    }

    public IDependencyScope BeginScope()
    {
        return new DefaultDependencyResolver(this.ServiceProvider.CreateScope().ServiceProvider);
    }

    public void Dispose()
    {
        // you can implement this interface just when you use .net core 2.0
        // this.ServiceProvider.Dispose();
        ((ServiceProvider)this.ServiceProvider).Dispose();
    }
}

 

public static class ServiceProviderExtensions
{
    public static IServiceCollection AddControllersAsServices(this IServiceCollection services,
                                                              IEnumerable<Type>       controllerTypes)
    {
        foreach (var type in controllerTypes)
        {
            services.AddTransient(type);
        }
 
        return services;
    }
}

 

public class DependencyInjectionConfig
{
    public static void Register(HttpConfiguration config)
    {
        var services = ConfigureServices();
        var builder  = ConfigureContainerBuilder(services);
        var provider = new AutofacServiceProvider(builder.Build());

        //var provider = services.BuildServiceProvider();

        var resolver = new DefaultDependencyResolver(provider);
        config.DependencyResolver = resolver;
    }

    /// <summary>
    ///     使用 Autofac 註冊
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    private static ContainerBuilder ConfigureContainerBuilder(IServiceCollection services)
    {
        var builder = new ContainerBuilder();
        builder.Populate(services);

        var assembly = Assembly.GetExecutingAssembly();
        builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();

        return builder;
    }

    /// <summary>
    ///     使用 MS DI 註冊
    /// </summary>
    /// <returns></returns>
    private static ServiceCollection ConfigureServices()
    {
        var services = new ServiceCollection();

        //使用 Microsoft.Extensions.DependencyInjection 註冊
        services.AddControllersAsServices(typeof(DependencyInjectionConfig)
                                          .Assembly
                                          .GetExportedTypes()
                                          .Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
                                          .Where(t => typeof(IHttpController).IsAssignableFrom(t)
                                                      || t.Name.EndsWith("Controller",
                                                                         StringComparison.OrdinalIgnoreCase)));

        //services.AddScoped<IMessager, LogMessager>();

        //services.AddTransient<ITransientMessager, MultiMessager>()
        //        .AddSingleton<ISingleMessager, MultiMessager>()
        //        .AddScoped<IScopeMessager, MultiMessager>();
        return services;
    }
}

 

public class DefaultController : ApiController
{
    private IMessager Messager { get; set; }

    public DefaultController(IMessager messager)
    {
        this.Messager = messager;
    }

    [HttpGet]
    public IHttpActionResult Get()
    {
        if (this.Messager == null)
        {
            var dependencyScope = this.Request.GetDependencyScope();
            this.Messager = dependencyScope.GetService(typeof(IMessager)) as IMessager;
        }

        var content = $"Messager:{this.Messager.OperationId}";
        return this.Ok(content);
    }
}

 

按下 F5 運行觀察

 

ASP.NET Core 3.1

新增 ASP.NET Core Web Application → API 專案範本,並安裝以下套件

Install-Package Autofac.Extensions.DependencyInjection

 

調用 .UseServiceProviderFactory(new AutofacServiceProviderFactory()) 方法

public class Program
{
    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        return Host.CreateDefaultBuilder(args)
                   .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                   .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
    }

    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
}

 

建立 ConfigureContainer 方法,這裡使用 Autofac 註冊

public class Startup
{
    ...
    public void ConfigureContainer(ContainerBuilder builder)
    {
        var assembly = Assembly.GetExecutingAssembly();
        builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
    }

    ...
}

 

[ApiController]
[Route("[controller]")]
public class DefaultController : ControllerBase
{
    private IMessager Messager { get; }

    private readonly ILogger<DefaultController> _logger;

    public DefaultController(ILogger<DefaultController> logger,
                             IMessager                  messager
    )
    {
        this._logger  = logger;
        this.Messager = messager;
    }

    [HttpGet]
    public IActionResult Get()
    {
        var content = $"Messager:{this.Messager.OperationId}";
        this._logger.LogInformation("Messager:{message}", content);
        return this.Ok(content);
    }
}

 

ASP.NET Core 套用 Autofac 的實作方式也是相當的簡單

 

專案位置

https://github.com/yaochangyu/sample.dotblog/tree/master/DI/Lab.MsDIForAutofac

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2019 .NET

Image result for microsoft+mvp+logo