使用 autofac 实现 asp .net core 的属性注入
使用 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使用 - 焰尾迭 - 博客园