.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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM