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

文章目录:.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 的同学们有所帮助!

 

 源码已经更新:https://github.com/xzhencheng/Sincere.Core

 

posted @ 2019-10-18 14:29  cheng序员  阅读(4022)  评论(11编辑  收藏  举报