zoukankan      html  css  js  c++  java
  • 【懒人有道】在asp.net core中实现程序集注入

    前言

    在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 = "xxoo123@outlook.com"
    22                     },
    23                 });
    24                 //设置xml注释文档,注意名称一定要与项目名称相同
    25                 var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "WebApi.xml");
    26                 options.IncludeXmlComments(filePath);
    27             });
    28         }

    但是,随着公司业务的扩大,系统项目的功能模块急剧扩张,新增了不下百个或者千个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     }
    附上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     }
    好了,到此就基本完成了,记得在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         }

    总结

    小记一下,好记性不如烂笔头。
  • 相关阅读:
    二、VueRouter ---kkb
    一、Vue组件化 ---kkb
    React项目的一些配置以及插件
    四、React全家桶(二)
    三、React全家桶(一)
    二、React组件化
    扩展欧几里得算法(含严谨证明)
    bzoj4034 树上操作
    欧几里得算法(含严谨证明)
    noip2013 车站分级
  • 原文地址:https://www.cnblogs.com/yanglang/p/6866165.html
Copyright © 2011-2022 走看看