使用 autofac 代替 asp .net core 默認的 IOC 容器,可實現屬性注入。
之前的使用方式不受影響。
源碼已開源:
dotnet-campus/Autofac.Annotation: Autofac 擴展,使用 Attribute 進行服務注冊與屬性注入
使用效果示例
向容器中注入服務
builder.RegisterType<Counter>().As<ICounter>().InstancePerDependency().AsImplementedInterfaces();
通過屬性獲取服務
[Autowired] // 這個不是 autofac 自帶的,是自己實現的,可以不要。見后面的詳述。
private ICounter Counter { get; set; }
准備工作
- nuget 引用
<PackageReference Include="Autofac" Version="5.2.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
- Program.cs 文件
使用autofac的容器工廠替換系統默認的容器
- Startup.cs 文件
在 Startup 服務配置中加入控制器替換規則
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
這句的意思:使用 ServiceBasedControllerActivator 替換 DefaultControllerActivator;Controller 默認是由 Mvc 模塊管理的,不在 Ioc 容器中。替換之后,將放在 Ioc 容器中。
在 Startup.cs 添加 public void ConfigureContainer(ContainerBuilder builder)
方法,這個方法會由 autofac 自動調用。
在這個方法中,進行依賴的注入和屬性注入的配置。
// 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 by the factory.
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule<BaseServiceRegisterModule>();
builder.RegisterModule<PropertiesAutowiredModule>();
}
在 autofac 中,有一個 Module 的概念,可以分模塊處理依賴的注入。試想,如果所有業務相關的依賴注入代碼,都放在 Startup.cs
這一個文件中,代碼會變得很難看。
這里的示例中,定義了 BaseServiceRegisterModule
和 PropertiesAutowiredModule
,分別寫服務注入的代碼,和屬性注入的配置代碼。
具體實現
下面把后面要說明的四個類都列出來:
public class BaseServiceRegisterModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
// Register your own things directly with Autofac, like:
builder.RegisterType<Counter>().As<ICounter>().InstancePerDependency().AsImplementedInterfaces();
}
}
public class PropertiesAutowiredModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
// 獲取所有控制器類型並使用屬性注入
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired(new AutowiredPropertySelector());
}
}
public class AutowiredPropertySelector: IPropertySelector
{
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(AutowiredAttribute));
}
}
[AttributeUsage(AttributeTargets.Property)]
public class AutowiredAttribute : Attribute
{
}
BaseServiceRegisterModule
中,向容器中注入了 ICounter
這個服務。
PropertiesAutowiredModule
中,配置了屬性注入的操作。這里是關鍵了。
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired(new AutowiredPropertySelector());
代碼還是挺直白的,需要說明
1 可以看到,屬性注入並不是 autofac 自動 幫我們完成的,得自己寫代碼,使用反射的方式,給哪些類進行屬性注入。
2 在上面的代碼中,只給 ControllerBase
的子類進行了屬性注入。
3 這里在 PropertiesAutowired
方法中,加了一個自定義的 AutowiredPropertySelector
。
如果沒有給 PropertiesAutowired
添加任何方法參數,則 autofac 會對所有屬性嘗試進行注入,PropertiesAutowired
的方法參數,可以指定屬性選擇器。
在本文的示例中,選擇器的實現是:
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(AutowiredAttribute));
}
也就是要求屬性必須顯式的標明 [Autowired]
這個 Attribute。
我這里這樣做的目的是為了讓代碼看起來更直觀,哪些屬性是自動注入的,哪些不是,一目了然。
最終效果
在依賴注冊上(向容器中添加服務),並沒有變化,還是需要手工寫代碼(在 Startup.cs 或者 Module 中),當然,也可以利用反射,自定義一個 Attribute,然后寫一端代碼自動將其注入到容器中。
在依賴注入上(從容器中獲取服務),這里可以利用屬性進行“自動”注入了。使用起來就是這樣 ↓,比 asp.net core 中只能是構造函數注入,方便了很多。
[Autowired]
private ICounter Counter { get; set; }
尾巴
對比 spring 框架,asp.net core 的 IOC 在易用性上,感覺還是弱了不少。不過看到這篇博客:ASP.NET Core 奇淫技巧之偽屬性注入 - 曉晨Master - 博客園,
覺得屬性注入不可濫用的說法還是有道理的,會造成依賴關系的隱藏。
參考文章
主要參考文章:
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使用 - 焰尾迭 - 博客園