一旦系统内模块比较多,按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 /// <summary> 2 /// 事件模块服务注册 3 /// </summary> 4 public class ServiceRegistrar : IServiceRegistrar 5 { 6 public int Order => 1; 7 8 public void Add(IServiceCollection services, IConfiguration configuration) 9 { 10 //event publisher 11 services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>(); 12 //event consumers 13 services.RegisterScope(typeof(Event.Abstractions.IConsumer<>)); 14 } 15 }