在Asp.Netcore内Panda.DynamicWebApi的使用方法,以及如何使用Panda.DynamicWebApi来使Controller何Server解耦
主题:Asp.netcore Code First +DDD学习笔记
目录:
【一】 CodeFirst+DDD项目结构的构建
【二】Asp.Netcore使用Panda.DynamicWebApi来进行Controller解耦
【三】Asp.NetCore使用Efcore+Mysql实现CodeFirst
【四】EfCore实现全自动化迁移
案例代码下载点击
当我们把Controller单独建成一个项目来解耦Controller后,Api那边进行了引用,发现接口并没有生成,但是我们需要接口生成。通过Abp我们知道了需要动态生成接口,于是找到了一个动态生成接口的组件:Panda.DynamicWebApi。
引用官方的一段话
Panda.DynamicWebApi
是一个动态生成WebApi的组件,生成的API符合Restful风格,受启发于ABP。它可以根据符合条件的类来生成WebApi,由MVC框架直接调用逻辑,无性能问题,完美兼容Swagger来构建API说明文档,与手动编写Controller相比并无区别。
应用场景:DDD架构中的应用逻辑层,可使用本组件来直接生成WebApi,而无需再用Controller来调用。
git地址:https://github.com/dotnetauth/Panda.DynamicWebApi/blob/master/README_zh-CN.md
【二】Controller使用Panda.DynamicWebApi
1、首先理解Panda.DynamicWebApi组件动态生成webApi的机制。
(1)要让类生成动态API需要满足两个条件,一个是该类直接或间接实现 IDynamicWebApi
,同时该类本身或者父抽象类或者实现的接口具有特性 DynamicWebApi
(2)添加特性 [NonDynamicWebApi]
可使一个类或者一个方法不生成API,[NonDynamicWebApi]
具有最高的优先级
更多机制请看git源码那里的第二步有详细介绍
2、开始载入组件
(1)在Api项目上管理Nuget包里面搜索并安装Panda.DynamicWebApi和Swashbuckle.AspNetCore(该组件时swagger组件),给Controller项目上安装Panda.DynamicWebApi,如图所示:
(2)在Api项目上注入该组件。
删除Api上面的Controller文件夹,使Api项目如下图所示
在Startup文件里的ConfigureServices方法下添加如下代码
//动态生成Api接口services.AddDynamicWebApi();//配置SwaggerApi自动生成器services.AddSwaggerGen(options =>{options.DocInclusionPredicate((docName, description) => true);//swagger支持动态生成的api接口options.CustomSchemaIds(type => type.FullName); //swagger支持动态生成的api接口options.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取代码运行的相对路径options.IncludeXmlComments(Path.Combine(basePath, "Api.xml"), true);//插入代码上的注释放入Swaggeroptions.IncludeXmlComments(Path.Combine(basePath, "ApiController.xml"), true);});
在Startup文件里的Configure方法下添加如下代码
//使用SwaggerApi自动生成器app.UseSwagger();//使用SwaggerApi自动生成器的Ui界面app.UseSwaggerUI(option =>{option.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");});
这样添加完成后,由于之前Api项目引用了Controller项目,只要Controller项目里面满足Panda.DynamicWebApi的接口生成机制(直接或间接实现 IDynamicWebApi+具有DynamicWebApi特性
)就会自动生成接口,并且会在swagger(不了解Swagger的可以点击来进行详细了解)上显示出来,如下:
在Controller项目添加一个TestController的测试类
代码如下:
using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;namespace Controller
{[DynamicWebApi]public class TestController : IDynamicWebApi{public string GetHelloWorld(){return "Hello World !!";}}
}
启动Api项目,将会在Swagger上看到该接口,如图:
(3)在上面的这些步骤,我们完成Controller的解耦,Controller的代码可以写在别的项目了,而主项目只需要添加对该项目的引用即可,在为了方便,我们不能每个接口都去实现IDynamicWebApi和标记DynamicWebApi特性,所以我们需要添加一个公共接口来继承和标记该特性,这样别的方法只需要继承即可。同理我们也可能需要每个接口都要有的一些通用的方法,所以我这里还写了一个Api的基类。
给Controller项目下添加一个Core(存放基类和通用方法的)的文件夹和一个Controllers(存放接口使用的)的文件夹如下所示:
注:这里的ApiController.xml是在swagger教程里面生成注释文件教程里面自动生成的。具体如何配置生成的请点击。这个注释文件一定要在Controller上配置,这样生成的swaggerApi文档才会有我们写的注释。
在Core里面添加一个IAppService接口文件和一个AppService类文件 如图所示:
这里面我扩展了两个在DDD里面比较通用的方法,本来打算用AutoMapper的,由于测试就没去用了,做Domain和Dto之间的映射还是AutoMapper好点(有个缺点是第一次映射还没我下面写的运行速度快,但是多次映射的话AutoMapper的性能还可以)
IAppService的代码如下
using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;
using System.Collections.Generic;namespace Controller.Core
{[DynamicWebApi]public interface IAppService : IDynamicWebApi{/// <summary>/// 传入实体内容,转化为对应的Dto/// </summary>/// <typeparam name="TDto">要转化的Dto类</typeparam>/// <param name="entity">传入的实体数据</param>/// <returns></returns>TDto EntityToDto<TDto>(object entity) where TDto : class, new();/// <summary>/// 传入List实体内容,转化为对应的List Dto/// </summary>/// <typeparam name="TDto"></typeparam>/// <param name="entityList">传入的List实体数据</param>/// <returns></returns>List<TDto> EntityToDto<TDto>(List<object> entityList) where TDto : class, new();}
}
AppService的代码如下
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;namespace Controller.Core
{public class AppService : IAppService{public AppService(){}/// <summary>/// 传入实体内容,转化为对应的Dto/// </summary>/// <typeparam name="TDto">要转化的Dto类</typeparam>/// <param name="entity">传入的实体数据</param>/// <returns></returns>public TDto EntityToDto<TDto>(object entity) where TDto : class, new(){return Entitytodto<TDto>(entity);}/// <summary>/// 传入List实体内容,转化为对应的List Dto/// </summary>/// <typeparam name="TDto"></typeparam>/// <param name="entityList">传入的List实体数据</param>/// <returns></returns>public List<TDto> EntityToDto<TDto>(List<object> entityList) where TDto : class, new(){List<TDto> list = new List<TDto>();foreach (var childObject in entityList){list.Add(Entitytodto<TDto>(childObject));}return list;}/// <summary>/// 传入实体内容,转化为对应的Dto/// </summary>/// <typeparam name="TDto"></typeparam>/// <param name="entity"></param>/// <returns></returns>private TDto Entitytodto<TDto>(object entity) where TDto : class, new(){TDto dto = new TDto();PropertyInfo[] propertyInfos = entity.GetType().GetProperties();PropertyInfo[] dtoproperty = dto.GetType().GetProperties();for (int i = 0; i < propertyInfos.Length; i++){for (int j = 0; j < dtoproperty.Length; j++){if (propertyInfos[i].Name == dtoproperty[j].Name){dtoproperty[j].SetValue(dto, propertyInfos[i].GetValue(entity));break;}}}return dto;}}
}
之后我们把TestController类移动到Controllers文件夹下 如图:
并修改代码(这里不需要实现IDynamicWebApi和标记DynamicWebApi特性
只需要继承我们自己的AppService, IAppService)如下:
using Controller.Core;namespace Controller.Controllers.Test
{/// <summary>/// 测试类/// </summary>public class TestAppService : AppService, IAppService{public string GetHelloWorld(){return "Hello World !!";}}
}
再次运行Api项目你可以看到Swagger上Test接口还是在的,如下:
到这里Controller从API里解耦出来已经初步经完成。
github地址:https://github.com/houliren/Asp.netcore-Code-First-DDD