.Net Core路由處理的知識點與方法總結
前言
用戶請求接口路由,應用返回處理結果。應用中如何匹配請求的數據呢?為何能如此精確的找到對應的處理方法?今天就談談這個路由。路由負責匹配傳入的HTTP請求,將這些請求發送到可以執行的終結點。終結點在應用中進行定義並且在應用啟動的時候進行配置,也就是在中間件中進行處理。
路由基礎知識
在項目新建的時候都會自動生成路由相關代碼。在Startup.Configure中的中間件管道註冊的。主要涉及到的則是UseRouting和UseEndpoints中間件。
UseRouting向中間件添加路由匹配。此中間件還會查看應用中定義的終結點集。也就是把應用中的路由統統註冊到中間件管道,方便請求的時候進行匹配。
UseEndpoints向中間件添加終結點執行。會運行相關聯的委托。簡單將就是路由匹配之後的處理事件運行。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); }); }
例如上面的代碼就是HTPP GET 請求並且Url是/的時候需要執行的委托、如果這裡的請求不是Get請求或者不是”/”,那麼沒有路由匹配,則會返回404。同時指定匹配模式的還有MapDelete、MapMethods、MapPost、MapPut、Map等。
終結點
上面講的MapGet或者未用到MapPost等就是用於定義終結點的。它們都包含有兩個參數,一個是用於Url匹配的,另外一個就是需要執行的委托。這裡在不一樣的應用中都采用瞭不同的終結點定義方法
- 用於 Razor Pages 的 MapRazorPages
- 用於控制器的 MapControllers
- 用於 SignalR 的 MapHub
- 用於 gRPC 的 MapGrpcService
那麼我們如果需要使用到瞭授權模塊將如何處理呢,終結點也有相對應的處理方式。下面就展示將授權中間件和路由一起使用,MapHealthChecks添加運行狀況檢查終結點。後面跟著的RequireAuthorization則是將授權策略添加到端點。
app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/healthz").RequireAuthorization(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); });
而且我們看中間的使用順序,UseAuthentication、UseAuthorization是穿插在UseRouting和UseEndpoints中間的,如此寫法則是為瞭授權策略能在UseRouting中查找終結點,但是能在UseEndpoints發送到終結點執行之前應用所選擇的授權策略
終結點元數據
上面的示例展示瞭運行狀況檢查終結點附加瞭授權策略。添加的授權策略是額外數據,也就是終結點元數據。
- 可以通過路由感知中間件來處理元數據。
- 元數據可以是任意的 .NET 類型。
上面提到元數據可以是人意的.NET類型,那麼具體到底是什麼呢?元數據如何使用呢?
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.Use(next => context => { var endpoint = context.GetEndpoint(); if (endpoint?.Metadata.GetMetadata<AuditPolicyAttribute>()?.NeedsAudit ==true) { Console.WriteLine("開始處理事務邏輯"); Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}"); } return next(context); }); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello world!"); }); // Using metadata to configure the audit policy. endpoints.MapGet("/sensitive", async context => { await context.Response.WriteAsync($"sensitive data{DateTime.UtcNow}"); }) .WithMetadata(new AuditPolicyAttribute(needsAudit: true)); }); } } public class AuditPolicyAttribute : Attribute { public AuditPolicyAttribute(bool needsAudit) { NeedsAudit = needsAudit; } public bool NeedsAudit { get; } }
看上面的示例中,在終結點綁定”/sensitive”的時候會附加元數據WithMetadata。當訪問“/”的時候會輸出”Hello world!”。但是在app.Use中並不會執行輸出”處理事務邏輯”,因為並沒有匹配的元數據。但是當執行”/sensitive”的時候就會輸出Console.WriteLine(“開始處理事務邏輯”);。因為在終結點定義的時候添加瞭元數據。元數據可以是人意.NET類型。上面的元數據也是我們自定義Class。
比較終端中間件和路由
上面我們使用app.Use來檢測匹配元數據,如果匹配成功我們就執行對應的操作。我們稱之為終端中間件,為什麼是終端中間件呢,因為這裡會停止搜索執行匹配和操作、最後返回。
那麼相比較下終端中間件和路由有什麼區別呢?
這兩種方法都允許終止處理管道:終端中間件允許在管道中的任意位置放置中間件:
- 中間件通過返回而不是調用 next 來終止管道。
- 終結點始終是終端。
終端中間件允許在管道中的任意位置放置中間件:
- 終結點在 UseEndpoints 位置執行。
終端中間件允許任意代碼確定中間件匹配的時間:
- 自定義路由匹配代碼可能比較復雜,且難以正確編寫。
- 路由為典型應用提供瞭簡單的解決方案。
- 大多數應用不需要自定義路由匹配代碼。
帶有中間件的終結點接口,如 UseAuthorization 和 UseCors。
- 通過 UseAuthorization 或 UseCors 使用終端中間件需要與授權系統進行手動交互
設置傳統路由
上面我們知道瞭通過UseRouting向中間件添加路由匹配,然後通過UseEndpoints定義終結點去執行匹配委托。那麼在MVC模式中如何設置呢?我們看看傳統路由的設置方法。
app.UseEndpoints(endpoints => { app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); });
上面我們設置傳統路由的時候采用的是endpoints.MapControllerRoute();,其中附帶有兩個參數,一個是名稱default,第二個則是路由模板。我們看路由模板{controller=Home}/{action=Index}/{id?},那麼在匹配Url路徑的時候,例如執行路徑 WeatherForecast/Index/5。那麼則會匹配控制器為WeatherForecast,其中方法是Index並且參數是int類型的一個處理方法。
REST Api 的屬性路由
上面講的是傳統路由設置,那麼對於Api項目的路由設置是如何的呢?REST Api 應使用屬性路由將應用功能建模為一組資源。我們看下示例代碼
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
在上面的代碼中使用MapControllers調用。映射屬性路由。我們看在使用的時候屬性路由的使用方式。
Route[]
下面的示例中我們采用的是Route[]的方式,它既可單獨作用域控制器也可單獨作用域action。也可同時使用。
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { [Route("Index")] public string Index(int? id) { return "Test"; } }
[ApiController] [Route("[controller]/[action]")] public class WeatherForecastController : ControllerBase { public string Index(int? id) { return "Test"; } }
[ApiController] public class WeatherForecastController : ControllerBase { [Route("[controller]/Index")] public string Index(int? id) { return "Test"; } }
Http[Verb]
采用Http[Verb]的方式那就僅僅能作用在action上瞭。比如下面的就直接在Index上方寫[HttpGet
("[controller]/Index")],其他就是HttpPost、HttpDelete等等操作 [ApiController] public class WeatherForecastController : ControllerBase { [HttpGet("[controller]/Index")] public string Index(int? id) { return "Test"; } }
Route[]和Http[Verb]混合使用
有時在實際運用中也可以采取兩種方式混合使用的,例如下面的示例在控制器采用Route[],在action采用Http[Verb]。因為一般定義Api的時候我們不僅要標註action名稱,我們還需要知道action的請求方式。
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet("Index")] public string Index(int? id) { return "Test"; } }
總結
到此這篇關於.Net Core路由處理的文章就介紹到這瞭,更多相關.Net Core路由處理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- None Found