大家好,我是張飛洪,感謝您的閱讀,我會不定期和你分享學習心得,希望我的文章能成為你成長路上的墊腳石,讓我們一起精進。
在本文中,我們将讨論ASP.NET Core中的新路由。我們将了解什麼是接口(endpoints)路由,它是如何工作的,它在哪裡使用,以及如何建立自己的路由。
本文主題:
- 探索接口路由
- 建立自定義接口
- 建立更複雜的接口
名詞定義:端點,即我們通路的接口或者叫API,有些地方叫EndPoint或者叫接口,其實源頭的稱呼應該叫端點會更貼切一些。或者你也可以直接叫EndPoint,但是先不管那麼多,大概了解這個意思就可以了。
探索接口路由
要了解接口路由(End Point),您需要了解什麼是端點以及什麼是路由。
端點是應用程式的一部分,當路由将傳入的請求映射到它時,端點就會被執行。
用戶端通常從伺服器請求資源。大多數情況下,用戶端是一個浏覽器。資源由指向特定目标的URL定義。除了網頁,它也可以是一個移動應用程式,從Web API請求特定JSON資料。
另一方面,執行的端點被映射到一個特定的路由,ASP.NET Core開發人員已經熟悉這樣一種路由模式:
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});
如果路由或路由模式與傳入請求的URL比對,則請求将映射到該端點。
ASP.NET Core可以映射到以下端點:
- Controllers (例如, MVC or web APIs)
- Razor Pages
- SignalR (and Blazor Server)
- gRPC services
-
Health checks
大多數端點都有非常簡單的路由模式。隻有MVC和Web API端點使用更複雜的模式。Razor頁面的路由定義基于實際頁面的檔案夾和檔案結構。
在ASP.NET Core 2.2中引入端點之前,路由隻是運用在MVC和Web API中。Razor Pages中的隐式路由是内置的,SignalR沒有路由一說。Blazor和gRPC在當時還不不知道在哪兒,健康檢查最初是作為中間件元件實作的。
引入端點路由是為了将路由與實際端點分離,說得白話一點,就是讓URL位址和實際執行的Action進行分離,這會讓架構更加靈活,同時這意味着新的端點不需要實作自己的路由。
建立自定義接口
建立端點的最簡單方法是使用lambda:
app.Map("/map", async context => {
await context.Response.WriteAsync("OK");
});
這裡将/map路由映射到一個簡單的端點,該端點将單詞“OK”寫入響應流。
關于早期.NET 6.0版本的說明
在.NET 6.0之前,該映射隻能在Startup.cs檔案中的UseEndpoints方法中,而使用.NET 6.0和新的Minimal API方法,可以在Program.cs檔案中完成映射。
另外,我們需要将Microsoft.AspNetCore.Http命名空間添加到using語句中。
還可以将特定的HTTP方法(如GET、POST、PUT和DELETE)映射到端點。以下代碼顯示了如何映射GET和POST方法:
app.MapGet("/mapget", async context => {
await context.Response.WriteAsync("Map GET");
});
app.MapPost("/mappost", async context => {
await context.Response.WriteAsync("Map POST");
});
我們還可以将兩個或多個HTTP方法映射到一個端點:
app.MapMethods("/mapmethods", new[] { "DELETE", "PUT" },
async context => {
await context.Response.WriteAsync("Map Methods");
});
這些端點映射很像我們在第8篇定制.NET 6.0的Middleware中間件中看到的基于lambda的中間件元件,這些管道中間件會傳回結果,例如基于HTML的視圖、JSON結構化資料或類似的内容。但是,端點路由是一種更靈活的輸出方式,它應該會在ASP.NET Core 3.0以後的所有版本中進行使用。
在第8篇中,我們看到我們可以像這樣的分支管道:
app.Map("/map", mapped => { // …… });
以上這種方式也會建立一個路由,但隻會偵聽以/map開頭的URL。如果您希望有一個處理/map/{id:int?}等模式的路由引擎,來比對/map/456而不是/map/abc,那麼您應該使用前面所述的新的路由。
而那些基于lambda的端點映射,對于簡單的場景非常有用。然而,由于它們是在Program.cs中定義的,如果您想使用這種方式來實作更複雜的場景,代碼維護性将變得很差。
是以,我們應該嘗試找到一種更結構化的方法來建立自定義端點。
建立更複雜的接口
接下來,我們将建立一個健康檢查接口例子,有點類似于您在Kubernetes叢集中運作應用程式時可能需要的接口,用來檢測系統的健康狀态:
我們從開發者的角度定義API接口,我們首先添加一個MapMyHealthChecks方法,作為IEndpointRouteBuilder對象上的一個擴充方法,它沒有實作:
app.MapMyHealthChecks("/myhealth");
app.MapControllerRoute(name: "default",pattern:"{controller=Home}/{action=Index}/{id?}");
為了避免混淆,我們這兒采取和之前類似的方式添加新接口,後面我們進一步來實作一下。
我們建立一個名為MapMyHealthChecksExtensions的靜态類,并在MapMyHealthCheck中放置一個擴充方法,該對象擴充IEndpointRouteBuilder接口并傳回IEndpointConventionBuilder對象:
namespace RoutingSample;
public static class MapMyHealthChecksExtensions {
public static IEndpointConventionBuilder MapMyHealthChecks (this IEndpointRouteBuilder endpoints, string pattern = "/myhealth")
{
// ...
}
}
以上隻是骨架,實際的接口将被實作為一個終止的中間件,也就是說,它不調用下一個的中間件元件,并建立響應流的輸出:
namespace RoutingSample;
public class MyHealthChecksMiddleware {
private readonly ILogger _logger;
public MyHealthChecksMiddleware (RequestDelegate next, ILogger logger)
{
_logger = logger;
}
public async Task Invoke(HttpContext context) {
// add some checks here...
context.Response.StatusCode = 200;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("OK");
}
}
實際工作是在Invoke方法中完成的。目前,隻示範200狀态碼和OK狀态響應,我們可以在這裡随意擴充該方法,例如檢查資料庫或相關服務的可用性。
接下來我們使用這個終止中間件,我們回到MapMyHealthChecks方法的架構。我們現在建立一個自己的管道,并将其映射到給定的pipeline:
var pipeline = endpoints.CreateApplicationBuilder().UseMiddleware().Build();
return endpoints.Map(pattern, pipeline).WithDisplayName("My custom health checks");
這種方法允許我們為這個新的管道添加更多的中間件。WithDisplayName擴充方法将配置的顯示名稱設定為接口,接下來按F5鍵啟動程式,并在浏覽器中調用https://localhost:7111/myhealth。我們将看到:
請注意,端口号可能會有所不同。我們還可以将已經存在的終止中間件元件轉換為路由接口,以配置更加靈活的路由。
總結
ASP.NET Core支援請求處理并向請求提供資訊的多種方法。接口路由是一種基于URL和請求的方法提供資源。
在本文,我們學習了如何使用終止中間件元件作為接口,并用将該接口映射到新的路由引擎,進而讓我們的路由變得更加強大和靈活。
每個Web應用程式都需要了解系統使用者,以允許或限制對特定資料的通路。在下一章中,我們将展示如何配置身份驗證和識别使用者。