zoukankan      html  css  js  c++  java
  • 使用 autofac 实现 asp .net core 的属性注入

    使用 autofac 代替 asp .net core 默认的 IOC 容器,可实现属性注入。
    之前的使用方式不受影响。

    使用效果示例

    向容器中注入服务

    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 这一个文件中,代码会变得很难看。

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

    具体实现

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

        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使用 - 焰尾迭 - 博客园

    原文链接:
    https://www.cnblogs.com/jasongrass/p/13457212.html

  • 相关阅读:
    Python面试题之装饰器漫谈
    Python入门之面向对象的__init__和__new__方法
    Python入门之PyCharm中目录directory与包package的区别
    Python中模块(Module)和包(Package)的区别
    详细讲解提高数据库查询效率的实用方法、外键关于性能
    kaptcha验证码插件的使用
    在 Web 项目中应用 Apache Shiro
    SessionFactory、HibernateTemplate、HibernateDaoSupport之间的关系说明
    jquery 绑定省份和城市
    jQuery事件之鼠标事件
  • 原文地址:https://www.cnblogs.com/jasongrass/p/13457212.html
Copyright © 2011-2022 走看看