[Lazy] implementing Assembly injection in asp.net core, asp. netcore
Preface in asp.net core, I have introduced DI containers. We can easily implement dependency injection without using third-party plug-ins. The following code: 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 test", 15 Version = "v1", 16 Description = "Swagger test RESTful API ", 17 TermsOfService = "None", 18 Contact = new Contact19 {20 Name = "", 21 Email = "xxoo123@outlook.com" 22}, 23 }); 24 // set the xml annotation document. Note that the name must be the same as the project name 25 var filePath = Path. combine (PlatformServices. default. application. applicationBasePath, "WebApi. xml "); 26 options. includeXmlComments (filePath); 27}); 28}View Code
However, with the expansion of the company's business, the functional modules of the system project have expanded dramatically, adding no more than or thousands of Repository and services (a bit exaggerated ...), at this time, it would be a bit cool to simply inject drops. Can I use reflection technology to inject an assembly ?? Try it. First, I will formulate some class name constraints without permission. The rules are set by yourself. For example:
- UserService --> IUserService
- UserRepository --> IUserRepository
- ......
- ClassName --> IClassName
Now let's start encoding: 1 /// <summary> 2 /// IServiceCollection extension 3 /// </summary> 4 public static class ServiceExtension 5 {6 /// <summary> 7 // implementation classes in the DI batch Injection Interface set. 8 /// <para> 9 /// note that the following conventions exist: 10 // IUserService --> UserService, IUserRepository --> UserRepository.11 /// </para> 12 /// </summary> 13 /// <param name = "service"> </param> 14 // <param name = "interfaceAssemblyName"> name of the interface assembly (excluding the file extension) </param> 15 // <returns> </returns> 16 public static IServiceCollection RegisterAssembly (this IServiceCollection service, string interfaceAssemblyName) 17 {18 if (servi Ce = 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 // filter out non-interface and generic interface 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 // The implementation class corresponding to the DI batch Injection Interface set. 44 // </summary> 45 // <param name = "service"> </param> 46 // <param name = "interfaceAssemblyName"> name of the interface assembly (excluding the file extension) </param> 47 // <param name = "implementAssemblyName"> name of the implementation assembly (excluding the file extension) </param> 48 // <returns> </returns> 49 public static IServiceCollection RegisterAssembly (this IServiceCollection service, string interfaceAssemblyName, string implementAssemblyName) 50 {51 if (service = null) 52 throw ne W 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 n Ew 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 // filter out non-interface and generic interface 71 var types = interfaceAssembly. getTypes (). where (t => t. getTypeInfo (). isInterface &&! T. getTypeInfo (). isGenericType); 72 73 foreach (var type in types) 74 {75 // filter out abstract classes, generic classes, and non-class76 var implementType = implementAssembly. definedTypes77. 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
The code for RuntimeHelper. cs is attached:
1 public class RuntimeHelper 2 {3 // <summary> 4 // obtain the project assembly and exclude all system assembly (Microsoft. * **, System. * **, etc.), Nuget download Package 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"); // exclude all system assembly and Nuget download package 12 foreach (var lib in libs) 13 {14 try15 {16 var assembly = AssemblyLoadContext. default. loadFromAssemblyName (new AssemblyName (lib. name); 17 list. add (assembly); 18} 19 catch (Exception) 20 {21 // ignored22} 23} 24 return list; 25} 26 27 public static Assembly GetAssembly (string assemblyName) 28 {29 return GetAllAssemblies (). firstOrDefault (assembly => assembly. fullName. C Ontains (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 <Typ E> (); 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
Okay, this is basically done. Remember to add the following to 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); // set the cache validity period to 5 minutes. 7 8 // Add framework services. 9 services. AddMvc (); 10 11 return services. BuilderInterceptableServiceProvider (builder => builder. SetDynamicProxyFactory (); 12}View Code
To sum up, note that a good memory is worse than a bad pen.