.netCore+Vue 搭建的简捷开发框架 (5)

  • 2019 年 10 月 18 日
  • 筆記

文章目录:.netCore+Vue 搭建的简捷开发框架–目录

上两节的内容介绍了一些关于。netCore 相关的一些基础知识。介绍这些的目的,最主要的还是为了我们的架构搭建服务。

上一节中,我们介绍了有关NetCore DI的一些概念。 整个框架,我们的仓储层、服务层都是通过依赖注入的方式进行加载调用的。

下面就来看一下仓储层和服务层是如何注入的:

 1 using System;   2 using System.Collections.Generic;   3 using System.Linq;   4 using System.Threading.Tasks;   5 using Microsoft.AspNetCore.Builder;   6 using Microsoft.AspNetCore.Hosting;   7 using Microsoft.AspNetCore.Mvc;   8 using Microsoft.EntityFrameworkCore;   9 using Microsoft.Extensions.Configuration;  10 using Microsoft.Extensions.DependencyInjection;  11 using Microsoft.Extensions.Logging;  12 using Microsoft.Extensions.Options;  13 using Sincere.Core.IRepository.Base;  14 using Sincere.Core.IServices.Base;  15 using Sincere.Core.Model.EFCore;  16 using Sincere.Core.Model.Models;  17 using Sincere.Core.Repository.Base;  18 using Sincere.Core.Services.Base;  19 using Sincere.Core.WebAPI.ServiceExtension;  20  21 namespace Sincere.Core.WebAPI  22 {  23     public class Startup  24     {  25         public Startup(IConfiguration configuration)  26         {  27             Configuration = configuration;  28         }  29  30         public IConfiguration Configuration { get; }  31  32         // This method gets called by the runtime. Use this method to add services to the container.  33         public void ConfigureServices(IServiceCollection services)  34         {  35             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);  36  37             services.AddDbContextPool<BaseCoreContext>(options =>  38                 options.UseSqlServer(BaseDBConfig.ConnectionString));  39             services.AddScoped<IBaseContext, BaseCoreContext>();  40             //泛型引用方式  41             services.AddScoped(typeof(IBaseServices<>), typeof(BaseServices<>));  42  43             services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));  44  45             services.RegisterAssembly("IServices");  46             services.RegisterAssembly("IRepository");  47         }  48  49         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  50         public void Configure(IApplicationBuilder app, IHostingEnvironment env)  51         {  52             if (env.IsDevelopment())  53             {  54                 app.UseDeveloperExceptionPage();  55             }  56  57             app.UseMvc();  58         }  59     }  60 }

View Code

 

 标记1 的部分,是关于EF,以及DbContext 的相关引用,这里涉及到一个AddDbContextPool的概念,我个人的理解就是可以把他当成我们使用ADO.net 时的数据库连接池。

另外需要说明的一点就是,采用AddScoped 的方式,整个数据库链接的上下文,在整个请求过程中,只会被实例化一次。

标记2的部分,时我们对仓储的基础类,和服务层基础类的引用,注意这些基础类是泛型的方式,所以引用的时候,需要采用泛型的方式来实现。在这个地方,刚开始的时候,不知道AddScoped支持泛型的方式,还写过一个工厂类来进行注入。

剩下的方法,services.RegisterAssembly 其实是一个比较巧妙的方式,为了避免每写一个service、repository就在ConfigureServices中注入一次。所以在这里采用了反射的机制。利用反射和我们的约定,将整个程序集中的Service和Repository进行一个引用。

webAPI工程下新建一个ServiceExtension目录,并添加RuntimeHelper类和ServiceExtension。

如下图:

 

 代码如下:

 1 using Microsoft.Extensions.DependencyInjection;   2 using System;   3 using System.Collections.Generic;   4 using System.Linq;   5 using System.Reflection;   6 using System.Threading.Tasks;   7   8 namespace Sincere.Core.WebAPI.ServiceExtension   9 {  10     /// <summary>  11     /// IServiceCollection扩展  12     /// </summary>  13     /// <summary>  14     /// IServiceCollection扩展  15     /// </summary>  16     public static class ServiceExtension  17     {  18         /// <summary>  19         /// 用DI批量注入接口程序集中对应的实现类。  20         /// <para>  21         /// 需要注意的是,这里有如下约定:  22         /// IUserService --> UserService, IUserRepository --> UserRepository.  23         /// </para>  24         /// </summary>  25         /// <param name="service"></param>  26         /// <param name="interfaceAssemblyName">接口程序集的名称(不包含文件扩展名)</param>  27         /// <returns></returns>  28         public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)  29         {  30             if (service == null)  31                 throw new ArgumentNullException(nameof(service));  32             if (string.IsNullOrEmpty(interfaceAssemblyName))  33                 throw new ArgumentNullException(nameof(interfaceAssemblyName));  34  35             var assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);  36             if (assembly == null)  37             {  38                 throw new DllNotFoundException($"the dll "{interfaceAssemblyName}" not be found");  39             }  40  41             //过滤掉非接口及泛型接口  42             var types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType);  43  44             foreach (var type in types)  45             {  46                 var implementTypeName = type.Name.Substring(1);  47                 var implementType = RuntimeHelper.GetImplementType(implementTypeName, type);  48                 if (implementType != null)  49                 {  50                     switch (serviceLifetime)  51                     {  52                         //根据条件,选择注册依赖的方法  53                         case ServiceLifetime.Scoped:  54                             //将获取到的接口和类注册进去  55                             service.AddScoped(type, implementType);  56                             break;  57                         case ServiceLifetime.Singleton:  58                             service.AddSingleton(type, implementType);  59                             break;  60                         case ServiceLifetime.Transient:  61                             service.AddTransient(type, implementType);  62                             break;  63                     }  64  65                 }  66             }  67             return service;  68         }  69  70  71     }  72 }

ServiceExtension.cs

 1 using Microsoft.Extensions.DependencyModel;   2 using System;   3 using System.Collections.Generic;   4 using System.Linq;   5 using System.Reflection;   6 using System.Runtime.Loader;   7 using System.Threading.Tasks;   8   9 namespace Sincere.Core.WebAPI.ServiceExtension  10 {  11     public class RuntimeHelper  12     {  13         /// <summary>  14         /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包  15         /// </summary>  16         /// <returns></returns>  17         public static IList<Assembly> GetAllAssemblies()  18         {  19             var list = new List<Assembly>();  20             var deps = DependencyContext.Default;  21             var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包  22             foreach (var lib in libs)  23             {  24                 try  25                 {  26                     var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));  27                     list.Add(assembly);  28                 }  29                 catch (Exception)  30                 {  31                     // ignored  32                 }  33             }  34             return list;  35         }  36  37         public static Assembly GetAssembly(string assemblyName)  38         {  39             return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName));  40         }  41  42         public static IList<Type> GetAllTypes()  43         {  44             var list = new List<Type>();  45             foreach (var assembly in GetAllAssemblies())  46             {  47                 var typeInfos = assembly.DefinedTypes;  48                 foreach (var typeInfo in typeInfos)  49                 {  50                     list.Add(typeInfo.AsType());  51                 }  52             }  53             return list;  54         }  55  56         public static IList<Type> GetTypesByAssembly(string assemblyName)  57         {  58             var list = new List<Type>();  59             var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));  60             var typeInfos = assembly.DefinedTypes;  61             foreach (var typeInfo in typeInfos)  62             {  63                 list.Add(typeInfo.AsType());  64             }  65             return list;  66         }  67  68         public static Type GetImplementType(string typeName, Type baseInterfaceType)  69         {  70             return GetAllTypes().FirstOrDefault(t =>  71             {  72                 if (t.Name == typeName &&  73                     t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name))  74                 {  75                     var typeInfo = t.GetTypeInfo();  76                     return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;  77                 }  78                 return false;  79             });  80         }  81     }  82 }

RuntimeHelper.cs

 

 这样类似的代码网上挺多的。大家可以参考借鉴一下。另外这个地方其实不用太过于关心反射带来的性能问题,因为只有在程序启动的时候,加载一次。

仓储层和服务层都注入进来以后,接下来就是怎么去使用了。

来一起看一下我们是怎么在ValuesController里面进行实现的。

 

  1.定义服务层接口

 2.在ValuesController初始化的时候,将服务层接口注入进来。

 3.使用接口,调用数据。

代码如下:

 1 using System;   2 using System.Collections.Generic;   3 using System.Linq;   4 using System.Threading.Tasks;   5 using Microsoft.AspNetCore.Mvc;   6 using Sincere.Core.IServices;   7   8 namespace Sincere.Core.WebAPI.Controllers   9 {  10     [Route("api/[controller]")]  11     [ApiController]  12     public class ValuesController : ControllerBase  13     {  14         readonly IAdvertisementServices _advertisementServices;  15         public ValuesController(IAdvertisementServices advertisementServices)  16         {  17             _advertisementServices = advertisementServices;  18         }  19  20         // GET api/values  21         [Route("")]  22         [HttpGet]  23         public async Task<ActionResult<IEnumerable<string>>> Get()  24         {  25             var t = await _advertisementServices.ReadAllAd();  26  27             return new string[] { "value1", "value2" };  28         }  29  30         // GET api/values/5  31         [HttpGet("{id}")]  32         public ActionResult<string> Get(int id)  33         {  34             return "value";  35         }  36  37         // POST api/values  38         [HttpPost]  39         public void Post([FromBody] string value)  40         {  41         }  42  43         // PUT api/values/5  44         [HttpPut("{id}")]  45         public void Put(int id, [FromBody] string value)  46         {  47         }  48  49         // DELETE api/values/5  50         [HttpDelete("{id}")]  51         public void Delete(int id)  52         {  53         }  54     }  55 }

View Code

关于ReadAllAd()方法,之前的章节中已经有过描述。

 

 调用成功,说明框架的整体流程已经跑通了!晚上加个鸡腿,庆祝一下!

按照之前的脑图,不知道大家还记得不?

 

 

红框里面的内容,到这一节,基本就结束了。接下来,会逐步的丰富我们的框架。加入日志,异常处理,权限验证。以及其他脑图中列出来的内容。

希望整个过程对于想学习、了解netCore 的同学们有所帮助!

 

 

最近又要离职了。心情比较复杂!可能更新不及时。还望海涵!