基於autofac的屬性注入
什麼是屬性注入
在瞭解屬性注入之前,要先了解一下DI(Dependency Injection),即依賴注入。在ASP.NET Core裡自帶了一個IOC容器,而且程式支行也是基於這個容器建立起來的,在 Startup 裡的 ConfigureService
方法裡向容器註冊服務型別。
簡單來說,依賴注入就是容器幫我們“new”一個物件,並且管理物件的生命週期。
在依賴注入時,最常用的是構造方法注入。還有另一種方法,那就是屬性注入。
在ASP.NET Core中,自帶的容器是不支援屬性注入的,但是可以通過替換容器來實現,也就是今天介紹的:通過 Autofac 來實現屬性注入。
autofac簡介
Autofac 是一款超讚的.NET IoC 容器 . 它管理類之間的依賴關係, 從而使 應用在規模及複雜性增長的情況下依然可以輕易地修改 . 它的實現方式是將常規的.net類當做 元件 處理.
中文文件:https://autofaccn.readthedocs.io/zh/latest/
為什麼要使用屬性注入
主要有以下三點:
- 減少常用型別的重複注入程式碼,使構造方法看起來更為簡潔,提高閱讀性。
- 減少或消除因構造方法注入造成子類繼承後的 base 呼叫鏈。
- 並非是滿足第一條或第二條就需要使用屬性注入來解決,只有當第一、二條發生的情況到達一定的數量。
具體實現
1、引用類庫
Autofac
Autofac.Extensions.DependencyInjection
2、在 Program.cs
裡替換系統預設容器
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory()) // 使用 autofac 的容器工廠替換系統預設的容器
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
3、在 Startup.cs
的 ConfigureServices
裡替換控制器的替換規則
public void ConfigureServices(IServiceCollection services)
{
// 替換控制器的替換規則
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
// other configure
services.AddControllers();
}
4、建立 AutowiredAttribute.cs
,用於標識使用屬性注入
[AttributeUsage(AttributeTargets.Property)]
public class AutowiredAttribute : Attribute
{
}
5、建立 AutofacModule.cs
,註冊服務
/// <summary>
/// 容器註冊類
/// </summary>
public class AutofacModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
// Register your own things directly with Autofac, like:
builder.RegisterType<HelloService>().As<IHelloService>().InstancePerDependency().AsImplementedInterfaces();
// 獲取所有控制器型別並使用屬性注入
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired(new AutowiredPropertySelector());
}
}
/// <summary>
/// 屬性注入選擇器
/// </summary>
public class AutowiredPropertySelector : IPropertySelector
{
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
// 帶有 AutowiredAttribute 特性的屬性會進行屬性注入
return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(AutowiredAttribute));
}
}
6、在 Startup.cs
的 方法 ConfigureContainer
裡註冊上一步建立的 Module
類
// ConfigureContainer is where you can register things directly
// with Autofac. This runs after ConfigureServices so the things
// here will override registrations made in ConfigureServices.
// Don't build the container; that gets done for you. If you
// need a reference to the container, you need to use the
// "Without ConfigureContainer" mechanism shown later.
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacModule());
}
示例程式碼下載:原始碼
使用效果
[Autowired]
private IHelloService HelloService { get; set; }
在控制器裡新增服務屬性,然後新增 [Autowired]
特性標識為屬性注入即可。
關於屬性注入的注意事項
屬性注入很好用,但是要慎重使用,因為屬性注入會造成型別的依賴關係隱藏,測試不友好等。
建議:在封閉框架時可以使用,但不能大範圍使用,只有必須使用屬性注入來達到效果的地方才會使用,用來提高使用框架時的編碼效率,來達到一些便利,脫離框架層面,編寫業務程式碼時,不得使用。
參考資料
主要參考文章:
使用 autofac 實現 asp .net core 的屬性注入
ASP.NETCore 3.0 Autofac替換及控制器屬性注入及全域性容器使用 - 情·深 - 部落格園
autofac 的官方示例:
autofac/Examples: Example projects that consume and demonstrate Autofac IoC functionality and integration
autofac 文件:
Welcome to Autofac’s documentation! — Autofac 5.2.0 documentation
歡迎來到 Autofac 中文文件! — Autofac 4.0 文件
其它:
ASP.NET Core 奇淫技巧之偽屬性注入 - 曉晨Master - 部落格園
.net core2.0下Ioc容器Autofac使用 - 焰尾迭 - 部落格園