在我們開發項目的Web API的時候,隨著項目功能要求越來越多,可能我們會為控制器基類增加越來越多的基礎功能,有些功能有一定的適應性,但可能在一般的子類中用不到,而隨著對控制器控制要求越來越精細,那麼需要為基類或者子類增加更多的控制功能,這樣隨著迭代的進行,有些控制器的功能會顯得越來越笨重。這個時候... ...
在我們開發項目的Web API的時候,隨著項目功能要求越來越多,可能我們會為控制器基類增加越來越多的基礎功能,有些功能有一定的適應性,但可能在一般的子類中用不到,而隨著對控制器控制要求越來越精細,那麼需要為基類或者子類增加更多的控制功能,這樣隨著迭代的進行,有些控制器的功能會顯得越來越笨重。這個時候,一種更加靈活、輕便的Web API處理方式,對每個控制器方法的垂直切割的API框架應運而生,本篇隨筆介紹的FastEndpoints 就是其中這樣的一款框架,本篇隨筆介紹一些FastEndpoints的基礎處理方法,並通過一些基礎的案例,把我們《 SqlSugar 開發框架》的一些模塊進行遷移性測試,對比相關後端Web API的處理,一起分享給大家。
1、FastEndpoints介紹
FastEndpoints 是Minimal API和MVC的開發人員友好替代品,它是基於REPR設計模式(請求-端點-響應),以便創建方便且可維護的端點,幾乎沒有樣板文件。
FastEndpoints 的性能與Minimal API 相當,甚至它更快,使用更少的記憶體並且每秒請求數比基準測試中的MVC控制器更高。對於比如:中間件、認證、授權、日誌,依賴註入這些常用功能都支持,甚至有些還進行了加強。
設計主要是分為兩種模式
分層模式:mvc、mvp、mvvm等
垂直模式:REPR設計模式
REPR設計模式就是垂直模式,系統的每個組件都是單獨的一塊,彼此並不影響,就像微服務那樣。
MVC - 模型-視圖-控制器旨在與用戶界面配合使用。顯然,視圖是一個 UI 組件。如果您正在構建 API,則沒有視圖,因此您充其量使用的是 MC 模式,或者您可以將其稱為模型-操作-控制器並獲取 MAC 模式。關鍵是,你已經沒有將MVC用於你的API,所以考慮一個更合適的模式應該不是一個很大的問題。
API 端點是非常獨立的,每個端點都可以使用三個組件來描述:
請求(Request):終結點所需的數據形狀
終結點(Endpoint):終結點在給定請求時執行的邏輯
響應(Response):終結點返回給調用方的響應
結合這三個元素,你會得到請求-端點-響應或 REPR 模式。
並非所有終結點都需要其請求或響應的實際數據,在某些情況下,不接收任何輸入或僅返回 HTTP 狀態代碼。但是,在此模式中,空請求或響應仍然是有效的請求或響應,就像某些 MVC 操作不需要模型一樣。
使用 API 端點庫時,您可以將請求、終端節點和響應類型分組在一起,這樣就無需在某些“視圖模型”或“dtos”文件夾中四處尋找合適的類型。它減少了摩擦,使使用單個端點變得更加容易。
FastEndPoint GitHub庫:https://github.com/FastEndpoints/FastEndpoints
FastEndpoints 線上文檔:https://fast-endpoints.com
2、簡單例子入門
參考官方的文檔介紹,我們可以很容易的創建出一個簡單的類似Hello開篇的API應用。
我創建一個基於.net core的Web API項目,先把FastEndPoint的相關引用加入項目中,如下所示。
然後在項目中的啟動類代碼中,我們添加相關的代碼使用FastEndpoints,如下所示。
using FastEndpoints; using FastEndpoints.Swagger; var bld = WebApplication.CreateBuilder(); bld.Services .AddFastEndpoints() .SwaggerDocument(); var app = bld.Build(); app.UseFastEndpoints() .UseSwaggerGen(); app.Run();
如果需要對Swagger進行一些定製修改,可以改動如下,這裡先忽略。
.SwaggerDocument(o => { o.DocumentSettings = s => { s.Title = "SqlSugar框架介面API文檔"; s.Version = "v1"; }; o.TagDescriptions = t => { t["Test"] = "測試介面"; t["User"] = "用戶相關介面"; }; })
為了簡便,我們以命名控制項不同,以及目錄,來區分不同的Web API分組,如下所示,我們創建一個基於Test的相關API介面。
對於以前的控制器介面來說,一般可能一個控制(如TestController)會包含多個方法,如上面的Create、List方法,這裡使用的是FastEndpoints,它們是把一個大型的控制器切換為一個方法一個類來處理,碎片化意味著類的增加,不過我們不需要做太多的工作,可以通過它們的一些基類來簡化這個過程。
我們把WebAPI中請求的Request和Response的對象,放在一個Model類文件裡面,如下代碼所示。
namespace FastWebApi.Controllers.Test { /// <summary> /// 測試請求信息 /// </summary> public class TestRequest { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } /// <summary> /// 測試返回信息 /// </summary> public class TestResponse { public string FullName { get; set; } public bool IsOver18 { get; set; } } }
我們來看看基於FastEndPoints方式 生成一個Create的請求Web API方法,如下代碼所示
namespace FastWebApi.Controllers.Test { //客戶使用標識,不用覆蓋 Configure 函數 //[HttpPost("/api/user/create")] //[AllowAnonymous] /// <summary> /// 創建記錄 /// </summary> public class Create : Endpoint<TestRequest, AjaxResponse> { public override void Configure() { Post("/test/create"); AllowAnonymous(); } public override async Task HandleAsync(TestRequest req, CancellationToken ct) { var result = new TestResponse() { FullName = req.FirstName + " " + req.LastName, IsOver18 = req.Age > 18 }; await SendAsync(result.ToAjaxResponse()); } } }
我們配置Web API方法的路由,可以通過在Configure函數中指定: Post("/test/create")
也可以通過Attribute屬性標識的方式,來聲明,上面的註釋代碼所示。
[HttpPost("/api/user/create")]
這兩者是等同的,任何一種方式都可以,預設的介面是需要授權才能訪問的,如果我們標識了
[AllowAnonymous]
就可以匿名訪問Web API 的方法了,Web API的方法處理邏輯,都是統一通過重寫 HandleAsync 方法進行實現的,如上面代碼所示。
其中AjaxResponse 是我定義的一個統一返回結果,這樣我們的介面模型就一致了。
如下是Web API統一封裝後返回的結果對象。
如果需要瞭解我的《SqlSugar開發框架》的統一結果返回處理,可以參考《基於SqlSugar的資料庫訪問處理的封裝,在.net6框架的Web API上開發應用 》中的 【統一結果封裝和異常處理】 部分內容即可。
如果不需要統一返回模型,則可以自定義為任何的返回類型,如下是官方的案例所示。
public class MyEndpoint : Endpoint<MyRequest, MyResponse> { public override void Configure() { Post("/api/user/create"); AllowAnonymous(); } public override async Task HandleAsync(MyRequest req, CancellationToken ct) { await SendAsync(new() { FullName = req.FirstName + " " + req.LastName, IsOver18 = req.Age > 18 }); } }
接下來,我們檢查下.netcore項目的launchSettings.json 配置信息
確保打開的時候就啟動Swagger頁面即可。
啟動Swagger頁面,我們來看看具體的效果,可以看到有兩個Test的介面,如下所示。
我們來調試Swagger,並測試下結果返回。
測試返回的結果如下所示,由於採用了統一返回結果的處理,這裡返回的TestResponse的對象序列化信息,放在了result的裡面了,如下所示。
而List的控制器方法,這裡沒有請求輸入的對象信息,因此參數為空。具體的API方法定義如下所示。
namespace FastWebApi.Controllers.Test { /// <summary> /// 獲取所有記錄 /// </summary> [HttpGet("/test/list")] [AllowAnonymous] public class List : EndpointWithoutRequest<AjaxResponse> { /// <summary> /// 處理返回 /// </summary> public override async Task HandleAsync(CancellationToken ct) { var result = new List<TestResponse>() { new TestResponse { FullName= "test", IsOver18 = true, }, new TestResponse { FullName= "test 2", IsOver18 = false, } }; await SendAsync(result.ToAjaxResponse()); } } }
Swagger介面展示界面效果。
正常執行返回結果如下所示。
如果處理過程中有異常,由於我們採用了統一返回結果處理,因此異常信息也需要統一在對象裡面,返回結果如下所示。
以上就是簡單類型的一些處理例子,結合了統一返回結果的處理,我們可以很好的定義一個通用的結果返回。
3、對我們SqlSugar框架常規CRUD等基類介面進行垂直切割的處理
上面我們為了更好理解FastEndpoints的碎片化介面的處理,我們做了兩個簡單的方法來測試。
下麵我們通過對我們《SqlSugar開發框架》中的基類介面進行功能上的拆分,並結合實際業務的需要介面,進行擴展的處理,從而也實現了常規CRUD的操作介面,並實現特殊業務類的API介面處理。
關於Web API的常規介面處理 ,我們為了簡化代碼,往往抽象一些常規的CRUD方法在控制器基類中,這樣可以極大的減少了繼承子類的介面代碼,通過繼承基類,子類自動具備了CRUD的處理介面,只需要根據業務的需要,增加一些特殊的業務介面即可。
以前的處理方法,我們是根據項目的需要,我們定義了一些控制器的基類,用於實現不同的功能,如下界面所示。
其中ControllerBase是.net core Web API中的標準控制器基類,我們由此派生一個LoginController用於登錄授權,而BaseApiController則處理常規介面用戶身份信息,而BusinessController則是對標準的增刪改查等基礎介面進行的封裝,我們實際開發的時候,只需要開發編寫類似CustomerController基類即可。
而現在採用FastEndpoints ,需要垂直切割整個控制器,這種架構稱為 “垂直切片架構", 系統的每個組件都是單獨的一塊,彼此並不影響,就像微服務那樣。
我們需要把基類的介面實現放到具體的業務API類裡面,為了方便,可以給它們不同的名稱一個介面,或者組合在一個文件裡面,如下所示。
我們來看看其中給一個簡單的Count方法介面實現。
namespace FastWebApi.Controllers.User { /// <summary> /// 根據條件計算記錄數量 /// </summary> [HttpGet("/user/count")] public class Count : Endpoint<UserPagedDto, AjaxResponse> { /// <summary> /// 處理請求 /// </summary> public override async Task HandleAsync(UserPagedDto req, CancellationToken ct) { var result = await BLLFactory<IUserService>.Instance.CountAsync(req); await SendAsync(result.ToAjaxResponse()); } } }
這裡可以採用介面註入的方式,也可以採用我們輔助類BLLFactory<IUserService>.Instance方法調用介面,一樣的實現。
這樣結合了業務的具體Service來處理,只需要簡單的處理下即可,也算比較方便,由於這些基礎的CRUD的方法,主要路由、分頁對象,業務對象,主鍵類型的不同,這些可以通過我們的代碼生成工具的處理快速生成即可,因此可以實現批量化的業務類的API介面方法生成。
至於具體的業務介面API,我們就需要手工處理了,如對於用戶的登陸獲取token的方法,我們這裡需要模仿來生成一個EndPiont類,如下所示。
/// <summary> /// 根據用戶名、密碼驗證用戶身份有效性 /// </summary> [HttpPost("/user/verify-user")] [AllowAnonymous] public class VerifyUser : Endpoint<VerifyUserDto, AjaxResponse> { /// <summary> /// 處理請求 /// </summary> public override async Task HandleAsync(VerifyUserDto input, CancellationToken ct) { var result = await BLLFactory<IUserService>.Instance.VerifyUser(input.UserName, input.UserPassword, input.SystemType, input.IP, input.MacAddr); await SendAsync(result.ToAjaxResponse()); } }
其他業務方法也是類似的處理,這裡的FastEndPoints的處理類,只是增加了一個簡單的包裝層就可以了,最後看看這些方法在SwaggerUI中的展示,和我們普通模式的Web API中的Swagger UI界面類似的效果。
這樣,我們可以在保持介面一致性的情況下,無縫的對接新的Web API介面後端了。

轉載請註明出處:撰寫人:伍華聰 http://www.iqidi.com