ASP.NET Core 奇淫技巧之动态WebApi
一.前言
接触到动态WebApi(Dynamic Web API)这个词的已有几年,是从ABP框架里面接触到的,当时便对ABP的这个技术很好奇,后面分析了一波,也尝试过从ABP剥离一个出来作为独立组件来使用,可是后来因与ABP依赖太多而放弃。十几天前朋友 熊猫 将这部分代码(我和他在搞事情)成功的从 ABP 中剥离出来并做了一个简单Demo扔给我,经过这么久(实在是太懒_)终于经过一些修改、添加功能、封装,现在已经能作为一个独立组件使用,项目开源在Github(https://github.com/dotnetauth/Panda.DynamicWebApi),希望觉得有用的朋友能给一个 Star 支持一下。
本文只讲使用,不讲原理,原理放到后面的文章中详细介绍。
二.介绍
不管是传统的三层架构、 DDD 经典四层架构(DDD Lite),亦或是其他具有应用逻辑层(业务逻辑层)的架构,在Web应用程序开发当中 ,我们的业务逻辑最终都需要经过 Web Api 来进行调用,这里我们可能会有一个重复的操作:编写业务逻辑->编写API调用业务逻辑,这种重复性的操作有没有解决办法呢,我们编写完业务逻辑以后便给我们自动生成WebApi,答案当然是有的。
这里介绍一下本文的主角:Panda.DynamicWebApi
(https://github.com/dotnetauth/Panda.DynamicWebApi)。源自于ABP的一个可独立使用的,可自动为你的业务逻辑层生成 ASP.NET Core WebApi 层的开源组件。它生成的API符合Restful风格,可以根据符合条件的类来生成WebApi,由MVC框架直接调用逻辑,无性能问题,完美兼容Swagger来构建API说明文档。
三.使用
这里以 DDD 经典四层架构中的应用逻辑层来讲解。
1.准备
(1)建立两个项目一个是应用逻辑层类库项目;一个是作为生成WebApi Host,ASP.NET Core WebApi项目
(2)编写应用逻辑
定义一个应用逻辑接口,所有应用逻辑都应实现它:
public interface IApplicationService
{
}
定义一个学生管理逻辑接口,继承应用逻辑接口
public interface IStudentAppService : IApplicationService
{
/// <summary>
/// 根据ID获取学生
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
StudentOutput Get(int id);
/// <summary>
/// 获取所有学生
/// </summary>
/// <returns></returns>
List<StudentOutput> Get();
/// <summary>
/// 更新学生信息
/// </summary>
/// <param name="input"></param>
void Update(UpdateStudentInput input);
/// <summary>
/// 更新学生年龄
/// </summary>
/// <param name="age"></param>
void UpdateAge(int age);
/// <summary>
/// 根据ID删除学生
/// </summary>
/// <param name="id"></param>
void Delete(int id);
/// <summary>
/// 添加学生
/// </summary>
/// <param name="input"></param>
void Create(CreateStudentInput input);
}
实现学生逻辑管理接口:
public class StudentAppService: IStudentAppService
{
/// <summary>
/// 根据ID获取学生
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id:int}")]
public StudentOutput Get(int id)
{
return new StudentOutput() {Id = 1, Age = 18, Name = "张三"};
}
/// <summary>
/// 获取所有学生
/// </summary>
/// <returns></returns>
public List<StudentOutput> Get()
{
return new List<StudentOutput>()
{
new StudentOutput(){Id = 1,Age = 18,Name = "张三"},
new StudentOutput(){Id = 2,Age = 19,Name = "李四"}
};
}
/// <summary>
/// 更新学生信息
/// </summary>
/// <param name="input"></param>
public void Update(UpdateStudentInput input)
{
throw new System.NotImplementedException();
}
/// <summary>
/// 更新学生年龄
/// </summary>
/// <param name="age"></param>
[HttpPatch("{id:int}/age")]
public void UpdateAge(int age)
{
throw new System.NotImplementedException();
}
/// <summary>
/// 根据ID删除学生
/// </summary>
/// <param name="id"></param>
[HttpDelete("{id:int}")]
public void Delete(int id)
{
throw new System.NotImplementedException();
}
/// <summary>
/// 添加学生
/// </summary>
/// <param name="input"></param>
public void Create(CreateStudentInput input)
{
throw new System.NotImplementedException();
}
}
(3)给 WebApi Host 项目配置 Swagger。
Install-Package Swashbuckle.AspNetCore -Version 4.0.1
Startup 中配置
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info { Title = "晓晨学生管理系统 WebApi", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.IncludeXmlComments(@"bin\Debug\netcoreapp2.2\Xc.StuMgr.WebApiHost.xml");
options.IncludeXmlComments(@"bin\Debug\netcoreapp2.2\Xc.StuMgr.Application.xml");
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "晓晨学生管理系统 WebApi");
});
app.UseMvc();
}
运行则会直接看到默认的 ValuesController 的5个API。
2.动态WebApi
通过Nuget 为 Application 项目安装组件:
Install-Package Panda.DynamicWebApi
为接口 IApplicationService
继承 IDynamicWebApi
同时添加特性DynamicWebApi
[DynamicWebApi]
public interface IApplicationService:IDynamicWebApi
{
}
在 WebApi Host 项目中,Startup里配置动态WebApi:
Startup.cs:
// 添加动态WebApi 需放在 AddMvc 之后
services.AddDynamicWebApi();
然后打开浏览器访问将会看到:
可以看到成功为我们的 StudentAppService
生成了WebApi,并且和Swagger完美兼容。
四.详细介绍
经过上面的介绍,大家应该可以看出使用是非常简单的,只需两步:
第一步:为你的类(或者该类的接口、该类继承的抽象类,不得放在该类除前面两种情况的父类上)继承 IDynamicWebApi
接口并加入特性[DynamicWebApi]
第二步:Startup中注册
// 添加动态WebApi 需放在 AddMvc 之后
services.AddDynamicWebApi();
因为需要MVC的一些类来进行处理,所以必须放在AddMvc之后,本组件有检查。
1.规则
本组件采用约定大于配置,所以在实际使用中有几个规则:
(1)要让类生成动态API需要满足两个条件,一个是该类直接或间接实现 IDynamicWebApi
,同时该类本身或者父抽象类或者实现的接口具有特性 DynamicWebApi
(2)添加特性 [NonDynamicWebApi]
可使一个类或者一个方法不生成API,[NonDynamicWebApi]
具有最高的优先级。
(3)会对符合规则的动态API类名进行后缀的删除,如:我们前面的 StudentAppService
,会被删除 AppService 后缀,这个规则是可以动态配置的。
(4)会自动添加API路由前缀,默认会为所有API添加 api
前缀
(5)默认的HTTP动词为POST
,可以通过 HttpGet/HttpPost/HttpDelete
等等ASP.NET Core 内置特性来覆盖
(6)可以通过HttpGet/HttpPost/HttpDelete
等内置特性来覆盖默认路由
(7)默认会根据你的方法名字来设置HTTP动词,如 CreateApple 或者 Create 生成的API动词为 POST
,对照表如下,若命中(忽略大小写)对照表那么该API的名称中的这个动词将会被省略,如 CreateApple 将会变成 Apple,如未在以下对照表中,将会使用默认动词 POST
方法名开头 | 动词 |
---|---|
create | POST |
add | POST |
post | POST |
get | GET |
find | GET |
fetch | GET |
query | GET |
update | PUT |
put | PUT |
delete | DELETE |
remove | DELETE |
(8)强烈建议方法名称使用帕斯卡命名(PascalCase)规范,以更好的自动处理API名称,且使用以上对照表的动词。如:
添加苹果 -> Add/AddApple/Create/CreateApple
更新苹果 -> Update/UpdateApple
...
(9)[DynamicWebApi]
特性因为可被继承,所以为了父类被误识别,禁止放在除抽象类、接口以外的父类上。
2.配置
所有的配置均在对象 DynamicWebApiOptions
中,说明如下:
属性名 | 是否必须 | 说明 |
---|---|---|
DefaultHttpVerb | 否 | 默认值:POST。默认HTTP动词 |
DefaultAreaName | 否 | 默认值:空。Area 路由名称 |
DefaultApiPrefix | 否 | 默认值:api。API路由前缀 |
RemoveControllerPostfixes | 否 | 默认值:AppService/ApplicationService。类名需要移除的后缀 |
RemoveActionPostfixes | 否 | 默认值:Async。方法名需要移除的后缀 |
FormBodyBindingIgnoredTypes | 否 | 默认值:IFormFile。不通过MVC绑定到参数列表的类型。 |
五.疑难解答
若遇到问题,可使用 Issues 进行提问。
六.结束
本项目开源地址:https://github.com/dotnetauth/Panda.DynamicWebApi 希望给个 Star 支持一下
本文Demo地址:XiaoChen.StudentManagement
ABP:https://github.com/aspnetboilerplate/aspnetboilerplate
ASP.NET Core 奇淫技巧之动态WebApi的更多相关文章
- ASP.NET Core 奇淫技巧之伪属性注入
一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上.还好当我度过了所谓的本命年后,许多事情都在慢慢变 ...
- [asp.net mvc 奇淫巧技] 04 - 你真的会用Action的模型绑定吗?
在QQ群或者一些程序的交流平台,经常会有人问:我怎么传一个数组在Action中接收.我传的数组为什么Action的model中接收不到.或者我在ajax的data中设置了一些数组,为什么后台还是接收不 ...
- [asp.net mvc 奇淫巧技] 06 - 也许你的项目同一个用户的请求都是同步的
一.感慨 很久前看到一篇博客中有句话大致的意思是:“asp.net 程序性能低下的主要原因是开发人员技术参差不齐”,当时看到这句话不以为然,然而时间过的越久接触的.net 开发人员越多就越认同这句话: ...
- Gradle更小、更快构建APP的奇淫技巧
本文已获得原作者授权同意,翻译以及转载原文链接:Build your Android app Faster and Smaller than ever作者:Jirawatee译文链接:Gradle更小 ...
- [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文
我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...
- 优化DP的奇淫技巧
DP是搞OI不可不学的算法.一些丧心病狂的出题人不满足于裸的DP,一定要加上优化才能A掉. 故下面记录一些优化DP的奇淫技巧. OJ 1326 裸的状态方程很好推. f[i]=max(f[j]+sum ...
- 12个实用的 Javascript 奇淫技巧
这里分享12个实用的 Javascript 奇淫技巧.JavaScript自1995年诞生以来已过去了16个年头,如今全世界无数的网页在依靠她完成各种关键任务,JavaScript曾在Tiobe发布的 ...
- NGINX的奇淫技巧 —— 5. NGINX实现金盾防火墙的功能(防CC)
NGINX的奇淫技巧 —— 5. NGINX实现金盾防火墙的功能(防CC) ARGUS 1月13日 发布 推荐 0 推荐 收藏 2 收藏,1.1k 浏览 文章整理中...... 实现思路 当服务器接收 ...
- NGINX的奇淫技巧 —— 3. 不同域名输出不同伺服器标识
NGINX的奇淫技巧 —— 3. 不同域名输出不同伺服器标识 ARGUS 1月13日 发布 推荐 0 推荐 收藏 6 收藏,707 浏览 大家或许会有这种奇葩的需求...要是同一台主机上, 需要针对不 ...
随机推荐
- how to make a function from using global var to not using it
let say, we want to find the bottom left node in a tree.one way to do it is using global vars: /** * ...
- END - 提交当前的事务
SYNOPSIS END [ WORK | TRANSACTION ] DESCRIPTION 描述 END END 提交当前事务. 所有当前事务做的修改都可被其它事务看到并且保证在发生崩溃的情况下的 ...
- Keil Debug (printf) Viewer
Debug (printf) Viewer Home » µVision Windows » Debug (printf) Viewer The Debug (printf) Viewer windo ...
- CPP-基础:文字常量区
内存不可写 char* 先看一个例子 ///////////// //代码1 #include <string> main() { char *buf = "good morni ...
- 剑指Offer(Python)
014-链表中倒数第k个结点 用快慢指针:p2比p1先走到k:间隔了k-1)步,然后再一起走,当p2为最后一个时,p1就为倒数第k个数 class ListNode: def __init__(sel ...
- Maven实战读书笔记(五):聚合与继承
Maven的聚合特性能够把项目的各个模块聚合在一起构建,而继承特性则能够帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能促进各个模块配置的一致性. 5.1 聚合 Maven聚合也称多模块 ...
- 【2018 CCPC网络赛】1003 - 费马小定理
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6440 这题主要是理解题意: 题意:定义一个加法和乘法,使得 (m+n)p = mp+np; 其中给定 ...
- Openjudge-4132-四则运算表达式求值
这一题我们可以通过递归求解,首先我们可以把一个表达式分为三部分,分别是: (1)表达式 :项.加减 (2)项:因子.乘除 (3)因子:数.()表达式 这三项构成了递归的关系,我们可以看到,要求一个表达 ...
- pytest以类形式的测试用例
from __future__ import print_function#pytest以类形式的测试用例class TestClass: @classmethod def setup_class(c ...
- 《算法导论》— Chapter 11 散列表
1 序 在很多应用中,都要用到一种动态集合结构,它仅支持INSERT.SEARCH以及DELETE三种字典操作.例如计算机程序设计语言的编译程序需要维护一个符号表,其中元素的关键字为任意字符串,与语言 ...