前言 在asp.net core中,我巨硬引入了DI容器,我們可以在不使用第三方插件的情況下輕鬆實現依賴註入。如下代碼: 1 // This method gets called by the runtime. Use this method to add services to the conta ...
前言
在asp.net core中,我巨硬引入了DI容器,我們可以在不使用第三方插件的情況下輕鬆實現依賴註入。如下代碼:1 // This method gets called by the runtime. Use this method to add services to the container. 2 public void ConfigureServices(IServiceCollection services) 3 { 4 //services.RegisterAssembly("IServices"); 5 services.AddSingleton<IUserService, UserService>(); 6 // Add framework services. 7 services.AddMvc(); 8 services.AddMvcCore() 9 .AddApiExplorer(); 10 services.AddSwaggerGen(options => 11 { 12 options.SwaggerDoc("v1", new Info() 13 { 14 Title = "Swagger測試", 15 Version = "v1", 16 Description = "Swagger測試RESTful API ", 17 TermsOfService = "None", 18 Contact = new Contact 19 { 20 Name = "來來吹牛逼", 21 Email = "[email protected]" 22 }, 23 }); 24 //設置xml註釋文檔,註意名稱一定要與項目名稱相同 25 var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "WebApi.xml"); 26 options.IncludeXmlComments(filePath); 27 }); 28 }View Code
但是,隨著公司業務的擴大,系統項目的功能模塊急劇擴張,新增了不下百個或者千個Repository和Service(有點誇張了...),這時候如此單純滴註入就有點操蛋了。
打懶主意
我可不可以通過反射技術來實現對程式集的註入呢??試試就試試
首先,我私自先制定一些類名的約束。規則嘛,反正是自己定。比如:- UserService --> IUserService
- UserRepository --> IUserRepository
- ......
- ClassName --> IClassName
1 /// <summary> 2 /// IServiceCollection擴展 3 /// </summary> 4 public static class ServiceExtension 5 { 6 /// <summary> 7 /// 用DI批量註入介面程式集中對應的實現類。 8 /// <para> 9 /// 需要註意的是,這裡有如下約定: 10 /// IUserService --> UserService, IUserRepository --> UserRepository. 11 /// </para> 12 /// </summary> 13 /// <param name="service"></param> 14 /// <param name="interfaceAssemblyName">介面程式集的名稱(不包含文件擴展名)</param> 15 /// <returns></returns> 16 public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName) 17 { 18 if (service == null) 19 throw new ArgumentNullException(nameof(service)); 20 if (string.IsNullOrEmpty(interfaceAssemblyName)) 21 throw new ArgumentNullException(nameof(interfaceAssemblyName)); 22 23 var assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); 24 if (assembly == null) 25 { 26 throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); 27 } 28 29 //過濾掉非介面及泛型介面 30 var types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); 31 32 foreach (var type in types) 33 { 34 var implementTypeName = type.Name.Substring(1); 35 var implementType = RuntimeHelper.GetImplementType(implementTypeName, type); 36 if (implementType != null) 37 service.AddSingleton(type, implementType); 38 } 39 return service; 40 } 41 42 /// <summary> 43 /// 用DI批量註入介面程式集中對應的實現類。 44 /// </summary> 45 /// <param name="service"></param> 46 /// <param name="interfaceAssemblyName">介面程式集的名稱(不包含文件擴展名)</param> 47 /// <param name="implementAssemblyName">實現程式集的名稱(不包含文件擴展名)</param> 48 /// <returns></returns> 49 public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName, string implementAssemblyName) 50 { 51 if (service == null) 52 throw new ArgumentNullException(nameof(service)); 53 if(string.IsNullOrEmpty(interfaceAssemblyName)) 54 throw new ArgumentNullException(nameof(interfaceAssemblyName)); 55 if (string.IsNullOrEmpty(implementAssemblyName)) 56 throw new ArgumentNullException(nameof(implementAssemblyName)); 57 58 var interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); 59 if (interfaceAssembly == null) 60 { 61 throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); 62 } 63 64 var implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName); 65 if (implementAssembly == null) 66 { 67 throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found"); 68 } 69 70 //過濾掉非介面及泛型介面 71 var types = interfaceAssembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); 72 73 foreach (var type in types) 74 { 75 //過濾掉抽象類、泛型類以及非class 76 var implementType = implementAssembly.DefinedTypes 77 .FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType && 78 t.GetInterfaces().Any(b => b.Name == type.Name)); 79 if (implementType != null) 80 { 81 service.AddSingleton(type, implementType.AsType()); 82 } 83 } 84 85 return service; 86 } 87 }View Code
附上RuntimeHelper.cs的代碼:
1 public class RuntimeHelper 2 { 3 /// <summary> 4 /// 獲取項目程式集,排除所有的系統程式集(Microsoft.***、System.***等)、Nuget下載包 5 /// </summary> 6 /// <returns></returns> 7 public static IList<Assembly> GetAllAssemblies() 8 { 9 var list = new List<Assembly>(); 10 var deps = DependencyContext.Default; 11 var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系統程式集、Nuget下載包 12 foreach (var lib in libs) 13 { 14 try 15 { 16 var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)); 17 list.Add(assembly); 18 } 19 catch (Exception) 20 { 21 // ignored 22 } 23 } 24 return list; 25 } 26 27 public static Assembly GetAssembly(string assemblyName) 28 { 29 return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName)); 30 } 31 32 public static IList<Type> GetAllTypes() 33 { 34 var list = new List<Type>(); 35 foreach (var assembly in GetAllAssemblies()) 36 { 37 var typeInfos = assembly.DefinedTypes; 38 foreach (var typeInfo in typeInfos) 39 { 40 list.Add(typeInfo.AsType()); 41 } 42 } 43 return list; 44 } 45 46 public static IList<Type> GetTypesByAssembly(string assemblyName) 47 { 48 var list = new List<Type>(); 49 var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); 50 var typeInfos = assembly.DefinedTypes; 51 foreach (var typeInfo in typeInfos) 52 { 53 list.Add(typeInfo.AsType()); 54 } 55 return list; 56 } 57 58 public static Type GetImplementType(string typeName, Type baseInterfaceType) 59 { 60 return GetAllTypes().FirstOrDefault(t => 61 { 62 if (t.Name == typeName && 63 t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name)) 64 { 65 var typeInfo = t.GetTypeInfo(); 66 return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType; 67 } 68 return false; 69 }); 70 } 71 }View Code
好了,到此就基本完成了,記得在Startup.cs加上:
1 // This method gets called by the runtime. Use this method to add services to the container. 2 public IServiceProvider ConfigureServices(IServiceCollection services) 3 { 4 services.RegisterAssembly("IServices"); 5 services.Configure<MemoryCacheEntryOptions>( 6 options => options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5));//設置緩存有效時間為5分鐘。 7 8 // Add framework services. 9 services.AddMvc(); 10 11 return services.BuilderInterceptableServiceProvider(builder => builder.SetDynamicProxyFactory()); 12 }View Code