使用 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; }
<PackageReference Include="Autofac" Version="5.2.0" /><PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
使用autofac的容器工厂替换系统默认的容器
在 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 文档:
Welcome to Autofac’s documentation! — Autofac 5.2.0 documentation
欢迎来到 Autofac 中文文档! — Autofac 4.0 文档
其它:
ASP.NET Core 奇淫技巧之伪属性注入 - 晓晨Master - 博客园
.net core2.0下Ioc容器Autofac使用 - 焰尾迭 - 博客园
如果需要更多更高级的功能,可以直接使用这个库:
yuzd/Autofac.Annotation: DI容器,依赖注入,AOP,动态代理等用注解来load autofac 摆脱代码或者xml配置和java的spring的注解注入一样的体验
原文链接: https://cloud.tencent.com/developer/article/2481503
本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。