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

2019-11-13 来源: 斗半米哥 发布在  https://www.cnblogs.com/migomiddle/p/11848358.html

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

1. 先来个dll助手

无外部依赖,可直接复用

 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 using System.Runtime.Loader;

 namespace Xms.Infrastructure.Utility
 {
     public class AssemblyHelper
     {
         public static List<Assembly> GetAssemblies(string searchPattern = "")
         {
             List<Assembly> assemblies = new List<Assembly>();
             if (searchPattern.HasValue())
             {
                 DirectoryInfo root = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
                 foreach (FileInfo f in root.GetFiles(searchPattern))
                 {
                     assemblies.Add(AssemblyLoadContext.Default.LoadFromAssemblyPath(f.FullName));
                 }
             }
             else
             {
                 assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
             }
             return assemblies;
         }

         public static List<Type> GetClassOfType(Type assignTypeFrom, string searchPattern = "")
         {
             var assemblies = GetAssemblies(searchPattern);
             var result = new List<Type>();
             try
             {
                 foreach (var a in assemblies)
                 {
                     Type[] types = a.GetTypes();

                     if (types == null)
                     {
                         continue;
                     }

                     foreach (var t in types)
                     {
                         if (!assignTypeFrom.IsAssignableFrom(t) && (!assignTypeFrom.IsGenericTypeDefinition || !DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
                         {
                             continue;
                         }

                         if (t.IsInterface)
                         {
                             continue;
                         }

                         if (t.IsAbstract)
                         {
                             continue;
                         }

                         result.Add(t);
                     }
                 }
             }
             catch (ReflectionTypeLoadException ex)
             {
                 var msg = string.Empty;
                 foreach (var e in ex.LoaderExceptions)
                 {
                     msg += e.Message + Environment.NewLine;
                 }

                 var fail = new Exception(msg, ex);
                 Debug.WriteLine(fail.Message, fail);

                 throw fail;
             }

             return result;
         }

         public static bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)
         {
             try
             {
                 var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();
                 foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))
                 {
                     if (!implementedInterface.IsGenericType)
                     {
                         continue;
                     }

                     var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
                     return isMatch;
                 }

                 return false;
             }
             catch
             {
                 return false;
             }
         }
     }
 }

2. 服务自动注册接口

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

 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;

 namespace Xms.Infrastructure.Inject
 {
     /// <summary>
     /// 服务自动注册接口
     /// </summary>
     public interface IServiceRegistrar
     {
         void Add(IServiceCollection services, IConfiguration configuration);

         int Order { get; }
     }
 }

3. DI服务扩展方法

 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using System;
 using Xms.Infrastructure.Inject;
 using Xms.Infrastructure.Utility;

 namespace Xms.Core
 {
     public static class ServiceCollectionExtensions
     {
         public static IServiceCollection RegisterAll(this IServiceCollection services, IConfiguration configuration)
         {
             var types = AssemblyHelper.GetClassOfType(typeof(IServiceRegistrar), "Xms.*.dll");
             foreach (var t in types)
             {
                 var instance = (IServiceRegistrar)Activator.CreateInstance(t);
                 instance.Add(services, configuration);
             }
             return services;
         }

         public static IServiceCollection RegisterScope<TService>(this IServiceCollection services)
         {
             var serviceType = typeof(TService);
             return Register(services, serviceType, ServiceLifetime.Scoped);
         }

         public static IServiceCollection RegisterScope(this IServiceCollection services, Type serviceType)
         {
             return Register(services, serviceType, ServiceLifetime.Scoped);
         }

         public static IServiceCollection Register(this IServiceCollection services, Type serviceType, ServiceLifetime serviceLifetime)
         {
             var implementTypes = AssemblyHelper.GetClassOfType(serviceType, "Xms.*.dll");
             if (serviceType.IsGenericType)
             {
                 foreach (var impl in implementTypes)
                 {
                     var it = impl.FindInterfaces((type, criteria) =>
                     {
                         var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
                         return isMatch;
                     }, serviceType);
                     foreach (var i in it)
                     {
                         services.Add(new ServiceDescriptor(i, impl, serviceLifetime));
                     }
                 }
             }
             else
             {
                 foreach (var impl in implementTypes)
                 {
                     services.Add(new ServiceDescriptor(serviceType, impl, serviceLifetime));
                 }
             }
             return services;
         }
     }
 }

4. 使用示例

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

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

相关文章