前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >使用 autofac 实现 asp .net core 的属性注入

使用 autofac 实现 asp .net core 的属性注入

作者头像
jgrass
发布2024-12-25 16:37:35
发布2024-12-25 16:37:35
8400
代码可运行
举报
文章被收录于专栏:蔻丁杂记蔻丁杂记
运行总次数:0
代码可运行

使用 autofac 代替 asp .net core 默认的 IOC 容器,可实现属性注入。

之前的使用方式不受影响。

源码已开源:

dotnet-campus/Autofac.Annotation: Autofac 扩展,使用 Attribute 进行服务注册与属性注入

更丰富的功能,可以看这里:

yuzd/Autofac.Annotation: Autofac extras library for component registration via attributes 用注解来load autofac 摆脱代码或者xml配置和java的spring的注解注入一样的体验

使用效果示例

向容器中注入服务

代码语言:javascript
代码运行次数:0
复制
builder.RegisterType<Counter>().As<ICounter>().InstancePerDependency().AsImplementedInterfaces();

通过属性获取服务

代码语言:javascript
代码运行次数:0
复制
[Autowired]  // 这个不是 autofac 自带的,是自己实现的,可以不要。见后面的详述。private ICounter Counter { get; set; }

准备工作

  • nuget 引用
代码语言:javascript
代码运行次数:0
复制
<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 自动调用。

在这个方法中,进行依赖的注入和属性注入的配置。

代码语言:javascript
代码运行次数:0
复制
// 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 这一个文件中,代码会变得很难看。

这里的示例中,定义了 BaseServiceRegisterModulePropertiesAutowiredModule ,分别写服务注入的代码,和属性注入的配置代码。

具体实现

下面把后面要说明的四个类都列出来:

代码语言:javascript
代码运行次数:0
复制
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();    }}
代码语言:javascript
代码运行次数:0
复制
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());    }}
代码语言:javascript
代码运行次数:0
复制
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 中,配置了属性注入的操作。这里是关键了。

代码语言:javascript
代码运行次数:0
复制
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 的方法参数,可以指定属性选择器。

在本文的示例中,选择器的实现是:

代码语言:javascript
代码运行次数:0
复制
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 中只能是构造函数注入,方便了很多。

代码语言:javascript
代码运行次数:0
复制
[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使用 - 焰尾迭 - 博客园

如果需要更多更高级的功能,可以直接使用这个库:

yuzd/Autofac.Annotation: DI容器,依赖注入,AOP,动态代理等用注解来load autofac 摆脱代码或者xml配置和java的spring的注解注入一样的体验

原文链接: https://cloud.tencent.com/developer/article/2481503

本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020年8月8日 |,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用效果示例
  • 准备工作
  • 具体实现
  • 最终效果
  • 尾巴
  • 参考文章
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档