微軟提供的 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~2022 .NET