ToB企服应用市场:ToB评测及商务社交产业平台

标题: .Net 依赖注入深入探索,做一个DI拓展,实现一个简易灵活的 主动依赖注入框 [打印本页]

作者: 欢乐狗    时间: 2024-9-30 14:22
标题: .Net 依赖注入深入探索,做一个DI拓展,实现一个简易灵活的 主动依赖注入框
一、依赖注入相关知识

1.1、依赖注入的原理和优点

1.2、.Net 服务注册

  1. // 将服务注册为接口
  2. services.AddTransient<IMyService, MyService>(); // 泛型注册
  3. services.AddScoped<IMyService, MyService>();
  4. services.AddSingleton<IMyService, MyService>();
  5. services.AddTransient<MyService>(); // 直接注册服务
  6. service.AddTransient(typeof(IMyService),typeof(MyService)); // 类型注册
  7. service.AddTransient(typeof(MyService));
复制代码
  1. MyService myService = new MyService(); // 先new一个实例,然后注册为单例模式服务
  2. services.AddSingleton(myService); // 直接注册
  3. services.AddSingleton<IMyService>(myService); // 注册为接口
复制代码
  1. builder.Services.Add(new ServiceDescriptor(typeof(IMyService), typeof(MyService), ServiceLifetime.Transient)); // 注册的服务类型,服务的实现类型,服务的生命周期
  2. builder.Services.Add(ServiceDescriptor.Transient(typeof(IMyService), typeof(MyService)));
  3. // 替换服务,已存在就替换;不存在,就新增
  4. builder.Services.Replace(ServiceDescriptor.Transient(typeof(IMyService), typeof(MyService))); // Replace:如果IMyService服务已存在,就替换;不存在,就新增。
复制代码
1.3、服务的三种生命周期类型,ServiceLifetime 枚举

Singleton 单例模式

Scoped 作用域模式

Transient 瞬时模式

1.6、服务注入、服务获取

  1. public class EFCoreController : ControllerBase
  2. {
  3.     IMyTestService _myTestService;
  4.     IServiceProvider _serviceProvider; // DI服务提供器,是单例模式。通过他可以获取到DI中所有单例、瞬时服务。若在某个服务作用域内,则也可以获取到所有作用域服务。此处控制器中,是在http请求的服务作用域内。
  5.     public EFCoreController(
  6.         IServiceProvider serviceProvider,
  7.         IMyTestService myTestService)
  8.     {
  9.         _myTestService = serviceProvider;
  10.         _myTestService = myTestService;
  11.         _serviceProvider.GetService<T>(); // 从DI中获取服务,若服务未创建,获取不到,返回 null
  12.         _serviceProvider.GetRequiredService<T>(); // 从DI中获取服务,若服务未创建,获取不到,则会抛异常
  13.     }
  14. }
复制代码
1.5、依赖注入高级用法

  1. var app = builder.Build();
  2. IServiceProvider rootServiceProvider = app.Services; // web程序运行时的DI,可以访问单例服务和瞬时服务,但无法访问作用域服务。
  3. using (IServiceScope serviceScope = rootServiceProvider.CreateScope()) // IServiceProvider.CreateScope() 创建一个服务作用域,此时所有作用域服务都会创建出来。
  4. {
  5.     IServiceProvider serviceProvider = serviceScope.ServiceProvider; // 使用服务作用域中的DI,可以访问 作用域服务
  6.     TestScopeService? testScopeService = serviceProvider.GetService<TestScopeService>(); // 测试拿到作用域服务实例
  7. }
复制代码
二、设计一个轻量级 主动依赖注入框架  【设计目的】

2.1、设计目的

2.2、使用示例

2.2.1、在要注入的服务类上,标注CoreDI特性,指定要注册的服务类型、注册的服务生命周期类型
  1. [CoreDI(typeof(ITestSigletonService), ServiceLifetime.Singleton)] // 将该服务以接口形式注册到DI(这个类必须是该接口的实现);指定生命周期类型
  2. public class TestSingletonService: ITestSigletonService
  3. {
  4.      public void Test()
  5.      {
  6.          Console.WriteLine("单例服务");
  7.      }
  8. }
  9. [CoreDI]  // 不指定接口,直接注册该类;不指定生命周期类型,默认是作用域生命周期
  10. public class TestScopeService
  11. {
  12.      public void Test()
  13.      {
  14.          Console.WriteLine("作用域服务");
  15.      }
  16. }
复制代码
2.2.2、将当前程序集类所有标注了CoreDI特性的服务,全部注入到DI
  1. builder.Services.AddCoreDIServices(typeof(TestSingletonService).Assembly);
复制代码
三、设计一个轻量级 主动依赖注入框架 【代码实现】

3.1、CoreDIAttribute
  1. /// <summary>
  2. /// 特性 将服务注入到DI中
  3. /// </summary>
  4. [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
  5. public class CoreDIAttribute : Attribute
  6. {
  7.     /// <summary>
  8.     /// 要注入的接口类型
  9.     /// </summary>
  10.     public Type? InterfaceType { get; private set; }
  11.     /// <summary>
  12.     /// 服务的生命周期
  13.     /// </summary>
  14.     public ServiceLifetime ServiceLifetime { get; private set; }
  15.     public CoreDIAttribute(Type? interfaceType = null, ServiceLifetime serviceLifeTime = ServiceLifetime.Scoped)
  16.     {
  17.         if (!Enum.IsDefined(serviceLifeTime))
  18.             throw new Exception($"【CoreDI】 The Enum '{nameof(ServiceLifetime)}' value error.");
  19.         InterfaceType = interfaceType;
  20.         ServiceLifetime = serviceLifeTime;
  21.     }
  22. }
复制代码
3.2、CoreDIServiceExtensions
  1. /// <summary>
  2. /// 依赖注入 拓展
  3. /// </summary>
  4. public static class CoreDIServiceExtensions
  5. {
  6.     /// <summary>
  7.     /// 将这些程序集中带有CoreDI特性的服务自动注入到DI容器
  8.     /// </summary>
  9.     public static void AddCoreDIServices(this IServiceCollection services, params Assembly[] assemblies)
  10.     {
  11.         // 找到这些程序集中包含CoreDI特性的所有服务,注册到DI
  12.         foreach (var assembly in assemblies)
  13.         {
  14.             Dictionary<Type, IEnumerable<CoreDIAttribute>> dic = assembly.GetTypes().ToDictionary(x => x, x => x.GetCustomAttributes<CoreDIAttribute>());
  15.             foreach (var item in dic)
  16.             {
  17.                 Type type = item.Key;
  18.                 IEnumerable<CoreDIAttribute> attributes = item.Value;
  19.                 if (attributes.Count() == 0)
  20.                     continue;
  21.                 foreach (CoreDIAttribute di in attributes)
  22.                 {
  23.                     if (di.InterfaceType != null && !type.GetInterfaces().Any(x => x == di.InterfaceType)) // 若服务注册为接口形式,则必须是该接口的实现类
  24.                         throw new Exception($"【CoreDI】 The Service '{type?.Name}' can not be resolving to the Service '{di.InterfaceType.Name}' ");
  25.                     services.Replace(new ServiceDescriptor(di.InterfaceType ?? type, type, di.ServiceLifetime)); // 使用服务描述类 ServiceDescriptor 将服务注册到DI,存在就替换,不存在就新增;从CoreDI特性中拿到指定的生命周期类型
  26.                 }
  27.             }
  28.         }
  29.     }
  30. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4