.netCore+Vue 搭建的简捷开发框架 (5)
文章目录:.netCore+Vue 搭建的简捷开发框架--目录
比奇小说网 m.biqi.org
上两节的内容介绍了一些关于。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
最近又要离职了。心情比较复杂!可能更新不及时。还望海涵!
以上是 .netCore+Vue 搭建的简捷开发框架 (5) 的全部内容, 来源链接: utcz.com/z/374748.html