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         }
    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          
    6             // Add framework services.
    7             services.AddMvc();
    8         }
    View Code

    总结

    小记一下,好记性不如烂笔头。
  • 相关阅读:
    .NET Interop 工具集
    关于正弦波的算法
    Windows Phone 系列 本地数据存储
    Xaml cannot create an instance of “X”
    Windows Phone 系列 使用 MVVM绑定时无法获取当前值
    Windows Phone 系列 应用程序图标无法显示
    Windows Phone 系列 WPConnect无法上网的问题
    Windows Phone 系列 使用 Windows Phone 保存铃声任务
    WP7.5提交应用
    Windows Phone 系列 动态删除ObservableCollection
  • 原文地址:https://www.cnblogs.com/zengxw/p/6864311.html
Copyright © 2011-2022 走看看