.netcore之DI批量注入(支持泛型) – xms

  • 2019 年 11 月 13 日
  • 筆記

一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介绍一下我在xms系统中应用的DI便捷工具:

1. 先来个dll助手

无外部依赖,可直接复用

  1 using System;    2 using System.Collections.Generic;    3 using System.Diagnostics;    4 using System.IO;    5 using System.Reflection;    6 using System.Runtime.Loader;    7    8 namespace Xms.Infrastructure.Utility    9 {   10     public class AssemblyHelper   11     {   12         public static List<Assembly> GetAssemblies(string searchPattern = "")   13         {   14             List<Assembly> assemblies = new List<Assembly>();   15             if (searchPattern.HasValue())   16             {   17                 DirectoryInfo root = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);   18                 foreach (FileInfo f in root.GetFiles(searchPattern))   19                 {   20                     assemblies.Add(AssemblyLoadContext.Default.LoadFromAssemblyPath(f.FullName));   21                 }   22             }   23             else   24             {   25                 assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());   26             }   27             return assemblies;   28         }   29   30         public static List<Type> GetClassOfType(Type assignTypeFrom, string searchPattern = "")   31         {   32             var assemblies = GetAssemblies(searchPattern);   33             var result = new List<Type>();   34             try   35             {   36                 foreach (var a in assemblies)   37                 {   38                     Type[] types = a.GetTypes();   39   40                     if (types == null)   41                     {   42                         continue;   43                     }   44   45                     foreach (var t in types)   46                     {   47                         if (!assignTypeFrom.IsAssignableFrom(t) && (!assignTypeFrom.IsGenericTypeDefinition || !DoesTypeImplementOpenGeneric(t, assignTypeFrom)))   48                         {   49                             continue;   50                         }   51   52                         if (t.IsInterface)   53                         {   54                             continue;   55                         }   56   57                         if (t.IsAbstract)   58                         {   59                             continue;   60                         }   61   62                         result.Add(t);   63                     }   64                 }   65             }   66             catch (ReflectionTypeLoadException ex)   67             {   68                 var msg = string.Empty;   69                 foreach (var e in ex.LoaderExceptions)   70                 {   71                     msg += e.Message + Environment.NewLine;   72                 }   73   74                 var fail = new Exception(msg, ex);   75                 Debug.WriteLine(fail.Message, fail);   76   77                 throw fail;   78             }   79   80             return result;   81         }   82   83         public static bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)   84         {   85             try   86             {   87                 var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();   88                 foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))   89                 {   90                     if (!implementedInterface.IsGenericType)   91                     {   92                         continue;   93                     }   94   95                     var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());   96                     return isMatch;   97                 }   98   99                 return false;  100             }  101             catch  102             {  103                 return false;  104             }  105         }  106     }  107 }

2. 服务自动注册接口

用于每个模块注册自己的服务,达到模块的高度自治的目的

 1 using Microsoft.Extensions.Configuration;   2 using Microsoft.Extensions.DependencyInjection;   3   4 namespace Xms.Infrastructure.Inject   5 {   6     /// <summary>   7     /// 服务自动注册接口   8     /// </summary>   9     public interface IServiceRegistrar  10     {  11         void Add(IServiceCollection services, IConfiguration configuration);  12  13         int Order { get; }  14     }  15 }

3. DI服务扩展方法

 1 using Microsoft.Extensions.Configuration;   2 using Microsoft.Extensions.DependencyInjection;   3 using System;   4 using Xms.Infrastructure.Inject;   5 using Xms.Infrastructure.Utility;   6   7 namespace Xms.Core   8 {   9     public static class ServiceCollectionExtensions  10     {  11         public static IServiceCollection RegisterAll(this IServiceCollection services, IConfiguration configuration)  12         {  13             var types = AssemblyHelper.GetClassOfType(typeof(IServiceRegistrar), "Xms.*.dll");  14             foreach (var t in types)  15             {  16                 var instance = (IServiceRegistrar)Activator.CreateInstance(t);  17                 instance.Add(services, configuration);  18             }  19             return services;  20         }  21  22         public static IServiceCollection RegisterScope<TService>(this IServiceCollection services)  23         {  24             var serviceType = typeof(TService);  25             return Register(services, serviceType, ServiceLifetime.Scoped);  26         }  27  28         public static IServiceCollection RegisterScope(this IServiceCollection services, Type serviceType)  29         {  30             return Register(services, serviceType, ServiceLifetime.Scoped);  31         }  32  33         public static IServiceCollection Register(this IServiceCollection services, Type serviceType, ServiceLifetime serviceLifetime)  34         {  35             var implementTypes = AssemblyHelper.GetClassOfType(serviceType, "Xms.*.dll");  36             if (serviceType.IsGenericType)  37             {  38                 foreach (var impl in implementTypes)  39                 {  40                     var it = impl.FindInterfaces((type, criteria) =>  41                     {  42                         var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());  43                         return isMatch;  44                     }, serviceType);  45                     foreach (var i in it)  46                     {  47                         services.Add(new ServiceDescriptor(i, impl, serviceLifetime));  48                     }  49                 }  50             }  51             else  52             {  53                 foreach (var impl in implementTypes)  54                 {  55                     services.Add(new ServiceDescriptor(serviceType, impl, serviceLifetime));  56                 }  57             }  58             return services;  59         }  60     }  61 }

4. 使用示例

比如下面的一个事件发布服务类,多个消费者服务类,实现了消费者的动态注册,大大提高了系统的灵活性、扩展性

1 //event publisher  2 services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>();  3 //event consumers  4 services.RegisterScope(typeof(Event.Abstractions.IConsumer<>));