zoukankan      html  css  js  c++  java
  • .Net Core5.0中Autofac依赖注入整合多层,项目中可直接用

    一、配置Autofac替换内置DI

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

    2.Program.cs中CreateHostBuilder方法后加上.UseServiceProviderFactory(new AutofacServiceProviderFactory()) ; 告诉程序要使用Autofac。

     3.Startup.cs中增加方法ConfigureContainer(ContainerBuilder containerBuilder),实例注入的地方,配置完成。

     /// <summary>
            /// Autofac注册服务的地方,Autofac会自动调用
            /// </summary>
            /// <param name="containerBuilder"></param>
            public void ConfigureContainer(ContainerBuilder containerBuilder)
            {
    
            }

    二、构造函数注入

    新建IUserService,类UserService,控制器UserController

     public interface IUserService
        {
            public string GetUserName();
        }
     public class UserService
        {
            public string GetUserName()
            {
                return "张三";
            }
        }
     public class UserController : Controller
        {
            private readonly IUserService _userService;
            public UserController(IUserService userService)
            {
                _userService = userService;
            }
            public IActionResult Index()
            {
                string name = _userService.GetUserName();
                return Content(name);
            }
        }

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

    瞬时注入:containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency();;

    单例注入:containerBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance();

    生命周期注入: containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();

     /// <summary>
            /// Autofac注册服务的地方,Autofac会自动调用
            /// </summary>
            /// <param name="containerBuilder"></param>
            public void ConfigureContainer(ContainerBuilder containerBuilder)
            {
                //注册服务
                containerBuilder.RegisterType<UserService>().As<IUserService>();
            }

    访问/User/Index,_userService成功注入,正确获取结果。

    三、属性注入

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

     public class UserController : Controller
        {
            [AutowiredProperty]
            private IUserService userService { get; set; }
            public IActionResult Index()
            {
                string name = userService.GetUserName();
                return Content(name);
            }
        }

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

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

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

     /// <summary>
        /// IPropertySelector:查看属性上是否标记某一个特性
        /// </summary>
       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容器中,在Startup.cs的ConfigureServices中增加

     //让控制器实例由容器创建
     services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

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

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

     6.验证结果,新增一个接口IOrderService.cs和一个实现类OrderService.cs做对比

     public interface IOrderService
        {
            public string CreateOrder();
        }
    
    public class OrderService : IOrderService
        {
            public string CreateOrder()
            {
                return "下单成功";
            }
        }

    把UserController改成

      public class UserController : Controller
        {
            [AutowiredProperty]
            private IUserService userService { get; set; }
    
            private IOrderService orderService { get; set; }//不加属性注入标识
            public IActionResult Index()
            {
                string name = userService.GetUserName();
                return Content(name);
            }
        }

    注入方法ConfigureContainer()增加

    containerBuilder.RegisterType<OrderService>().As<IOrderService>();

    运行程序,能看到增加了注入标识的userService注入成功,没加标识的orderService没有注入。

    四、批量注入

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

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

      /// <summary>
        /// 瞬时注入
        /// </summary>
        public interface ITransitDenpendency
        {
        }
      /// <summary>
        /// 单例注入标识
        /// </summary>
        public interface ISingletonDenpendency
        {
        }
       /// <summary>
        /// 生命周期注入标识
        /// </summary>
        public interface IScopeDenpendency
        {
        }

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

    3.新增一个IocManger类

      /// <summary>
            /// 批量注入扩展
            /// </summary>
            /// <param name="builder"></param>
            /// <param name="assembly"></param>
            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改成

     /// <summary>
            /// Autofac注册服务的地方,Autofac会自动调用
            /// </summary>
            /// <param name="containerBuilder"></param>
            public void ConfigureContainer(ContainerBuilder containerBuilder)
            {
                //获取所有控制器类型并使用属性注入
               Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
                   .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
                containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
    
                //批量自动注入,把需要注入层的程序集传参数
                containerBuilder.BatchAutowired(typeof(UserService).Assembly);
                containerBuilder.BatchAutowired(typeof(UserRepository).Assembly);
            }

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

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

    ConfigureContainer的代码变成

    /// <summary>
            /// Autofac注册服务的地方,Autofac会自动调用
            /// </summary>
            /// <param name="containerBuilder"></param>
            public void ConfigureContainer(ContainerBuilder containerBuilder)
            {
                containerBuilder.RegisterModule<AutofacRegisterModule>();
            }

    五、手动获取实例

    手动获取实例的场景有静态帮助类中获取实例,例如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;
                        }
                    }
                }
            }
            /// <summary>
            /// 手动获取实例
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            public static T Resolve<T>()
            {
                return _container.Resolve<T>();
            }

    2.在Startup.cs的Configure()中增加

    //获取Autofac容器上下文信息
    IocManager.InitContainer(app.ApplicationServices.GetAutofacRoot());

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

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

    修改UserController用DataHelper的方法成功获取数据

    六、其它用法

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

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

     2.一接口多实现

     public class UserService :IUserService
        {
            public string GetUserName()
            {
                return "张三";
            }
        }
    
     public class User2Service : IUserService
        {
            public string GetUserName()
            {
                return "张三2号";
            }
        }

    最后:源码地址:https://github.com/weixiaolong325/.NetCore5.0AutofacDemo

    演示项目结构:

  • 相关阅读:
    Java实现web页面内容抓取
    Java写入文件的几种方法及性能对比
    Java实现导出excel
    win10系统安装VMware虚拟机软件以及linux系统
    oracle11g安装教程
    oracle怎么建立本地连接
    工厂模式
    计算一个字符串中每个字符出现的次数
    MySql多表查询
    如何查看MySql的sql语句性能
  • 原文地址:https://www.cnblogs.com/wei325/p/15121451.html
Copyright © 2011-2022 走看看