• .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

  • 相关阅读:
    Ida动态修改android程序的内存数据和寄存器数值,绕过so文件的判断语句
    Ida双开定位android so文件
    IDA调试android so文件.init_array和JNI_OnLoad
    超EASY 五步实现Eclipse ASN.1 SDK和插件安装
    记录重装系统的艰苦奋斗历程
    音标
    有道建昆老师~Reading Comprehensive
    Linux之普通用户用sudo建立文件和root用户建立的区别
    名句
    20200307(13)
  • 原文地址:https://www.cnblogs.com/xuzhencheng/p/11698132.html
Copyright © 2020-2023  润新知