一.前言
接觸到動態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