• .NET7 中Autofac依赖注入整合多层,项目中可直接用


     


    一、配置Autofac替换内置DI

    1.安装Nuget包:Autofac.Extensions.DependencyInjection

     

    2.Program.cs中加上

    复制代码
    builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
    builder.Host.ConfigureContainer(containerBuilder =>
    {
        //在这里写注入代码
        
    });
    复制代码

     

     

    二、构造函数注入

     新建IUserService,类UserService

     public interface IUserService
        {
            public string GetUserName();
        }
    复制代码
     public class UserService:IUserService
        {
            public string GetUserName()
            {
                return "张三";
            }
        }
    复制代码

    在上面的ConfigureContainer方法把UserService注入进来,默认是瞬时注入

    瞬时注入:containerBuilder.RegisterType().As().InstancePerDependency();;

    单例注入:containerBuilder.RegisterType().As().SingleInstance();

    生命周期注入: containerBuilder.RegisterType().As().InstancePerLifetimeScope();

     注入试下是否注入成功

     调用成功,证明注入成功

     

    三、属性注入

    1.把HomeController改成属性注入形式,属性注入有一个问题,就是那些属性需要注入?全部注入没必要,父类也有很多属性,要按需注入,给属性增加一个自定义特性标识说明需要注入。

    复制代码
    public class HomeController : Controller
        {
            [AutowiredProperty]
            private IUserService userService { get; set; }
            public IActionResult Index()
            {
                string name = userService.GetUserName();
                  return View();
            }
        }
    复制代码

    2.新增自定义特性类AutowiredPropertyAttribute.cs

    [AttributeUsage(AttributeTargets.Property)]//为了支持属性注入,只能打到属性上
        public class AutowiredPropertyAttribute: Attribute
        {
        }

    3.增加识别特性类AutowiredPropertySelector.cs

    复制代码
    public class AutowiredPropertySelector : IPropertySelector
        {
            public bool InjectProperty(PropertyInfo propertyInfo, object instance)
            {
                //判断属性的特性是否包含自定义的属性,标记有返回true
                return propertyInfo.CustomAttributes.Any(s => s.AttributeType == typeof(AutowiredPropertyAttribute));
            }
        }
    复制代码

    4.因为Controller 默认是由 Mvc 模块管理的,需要把控制器放到IOC容器中,在Program.cs中增加

    //让控制器实例由容器创建
    builder.Services.Replace(ServiceDescriptor.Transient());

    5.把容器注册到IOC容器,在Program.cs的ConfigureContainer()增加

     //获取所有控制器类型并使用属性注入
        Type[] controllersTypeAssembly = typeof(Program).Assembly.GetExportedTypes()
            .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
        containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

     验证:

     成功。

    四、批量注入

    实际项目中那么多需要注入的类,一个个写注册就不太现实了,需要一个可以批量注入的方法。

    1.新建三个空接口IScopeDenpendency.cs,ISingletonDenpendency.cs,ITransitDenpendency.cs

    复制代码
    /// 
        /// 瞬时注入
        /// 
        public interface ITransitDenpendency
        {
        }
      /// 
        /// 单例注入标识
        /// 
        public interface ISingletonDenpendency
        {
        }
       /// 
        /// 生命周期注入标识
        /// 
        public interface IScopeDenpendency
        {
        }
    复制代码

    2.把上面要注入的类实现上面的接口

     3.新增一个IocManager类

    复制代码
    /// 
        /// Ioc管理
        /// 
        public static class IocManager
        {
            /// 
            /// 批量注入扩展
            /// 
            /// 
            /// 
            public static void BatchAutowired(this ContainerBuilder builder, Assembly assembly)
            {
    
                var transientType = typeof(ITransitDenpendency); //瞬时注入
                var singletonType = typeof(ISingletonDenpendency); //单例注入
                var scopeType = typeof(IScopeDenpendency); //单例注入
                //瞬时注入
                builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(transientType))
                    .AsSelf()
                    .AsImplementedInterfaces()
                    .InstancePerDependency()
                    .PropertiesAutowired(new AutowiredPropertySelector());
                //单例注入
                builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(singletonType))
                   .AsSelf()
                   .AsImplementedInterfaces()
                   .SingleInstance()
                   .PropertiesAutowired(new AutowiredPropertySelector());
                //生命周期注入
                builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(scopeType))
                   .AsSelf()
                   .AsImplementedInterfaces()
                   .InstancePerLifetimeScope()
                   .PropertiesAutowired(new AutowiredPropertySelector());
    
            }
    复制代码

    4.把注入类ConfigureContainer改成

     

    5.防止Program.cs代码过多,建一个Module把注入代码搬走,新建AutofacRegisterModule.cs类把ConfigureContainer的代码移过去

    复制代码
      public class AutofacRegisterModule : Autofac.Module
        {
            protected override void Load(ContainerBuilder builder)
            {
    
                //获取所有控制器类型并使用属性注入
                Type[] controllersTypeAssembly = typeof(Program).Assembly.GetExportedTypes()
                    .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
                builder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
                //批量自动注入,把需要注入层的程序集传参数,注入Service层的类
                builder.BatchAutowired(typeof(UserService).Assembly);
                //注入其它层的containerBuilder.BatchAutowired(typeof(其它层的任务一个类).Assembly);
            }
        }
    复制代码

    ConfigureContainer的代码变成

     

    五、手动获取实例

    手动获取实例的场景有静态帮助类中获取实例,例如redisHelper中获取注入的配置文件中的连接字符串

    1.在上面的IocManager类中增加

    复制代码
     private static object obj = new object();
     private static ILifetimeScope _container { get; set; }
    
      public static void InitContainer(ILifetimeScope container)
            {
                //防止过程中方法被调用_container发生改变
                if (_container == null)
                {
                    lock (obj)
                    {
                        if (_container == null)
                        {
                            _container = container;
                        }
                    }
                }
            }
            /// 
            /// 手动获取实例
            /// 
            /// 
            /// 
            public static T Resolve()
            {
                return _container.Resolve();
            }
    复制代码

    2.在Program.cs中增加

     3.验证,新建一个DataHelper.cs类

    复制代码
     public class DataHelper
        {
            //手动注入UserService
            private static IUserService userService = IocManager.Resolve();
            public static string GetData()
            {
                return userService.GetUserName();
            }
        }
    复制代码

     成功获取到值,证明从容器中获取成功。

    六、其它用法

    1.不用接口,直接注入实例

    复制代码
     public class UserService :ITransitDenpendency
        {
            public string GetUserName()
            {
                return "张三";
            }
        }
    复制代码

     

     2.一接口多实现

    复制代码
     public class UserService :IUserService
        {
            public string GetUserName()
            {
                return "张三";
            }
        }
    
     public class UserService2 : IUserService
        {
            public string GetUserName()
            {
                return "张三2号";
            }
        }
    复制代码

     

  • 相关阅读:
    flutter vscode gradle 配置
    Docker安装Yapi
    Spring使用注解开发
    从零开始Blazor Server(9)--修改Layout
    流行的前端开源报表工具有哪些?适合在企业级应用的
    MySQL:增量备份和恢复(5)
    ES 关于text和keyword两种类型数据搜索区别
    【如何让图片自适应盒子大小】
    考研成绩公布后,下一步应该怎么做?
    中级程序员——vue3+js+git面试题
  • 原文地址:https://www.cnblogs.com/wei325/p/17481596.html