程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> ASP.NET Core的路由[4]:來認識一下實現路由的RouterMiddleware中間件,

ASP.NET Core的路由[4]:來認識一下實現路由的RouterMiddleware中間件,

編輯:關於.NET

ASP.NET Core的路由[4]:來認識一下實現路由的RouterMiddleware中間件,


雖然ASP.NET Core應用的路由是通過RouterMiddleware這個中間件來完成的,但是具體的路由解析功能都落在指定的Router對象上,不過我們依然有必要以代碼實現的角度來介紹一下這個中間件。在這之前,我們先來認識一個特殊的特性。[本文已經同步到《ASP.NET Core框架揭秘》之中]

讓RouterMiddleware中間件委托Router完整整個路由工作之後,解析出來的路由參數會以一個RouteData對象的形式存儲在RouteContext上下文中。但是RouteContext是為Router的執行建立的上下文,路由解析工作完成之後,這個上下文的生命周期也隨著結束,既然整個RouteContext上下文都不存在了,請求處理的後續步驟如何獲取這個RouteData對象呢?

通過《注冊URL模式與HttpHandler的映射關系》的實例演示我們知道可以調用HttpContext的擴展方法GetRouteData來獲取這個包含素所有路由參數的RouteData對象,這個意味著原本依附於RouteContext上下文的RouteData最終會被附加到代表當前請求上下文的HttpContext上,而具體承載這個RouteData的就是這個名為RoutingFeature的特性。RoutingFeature是我們對所有實現了IRoutingFeature接口的所有類型以及對應對象的統稱。如下面的代碼片段所示,這個接口通過屬性RouteData來保存最終附加到HttpContext的RouteData。RoutingFeature類是這個接口的默認實現者,我們的RouterMiddleware默認情況下就是使用這個對象。

   1: public interface IRoutingFeature
   2: {
   3:     RouteData RouteData { get; set; }
   4: }
   5:  
   6: public class RoutingFeature : IRoutingFeature
   7: {
   8:     public RouteData RouteData { get; set; }
   9: }

如下所示的代碼片段體現了RouterMiddleware處理請求的完整邏輯。我們在創建一個RouterMiddleware對象的時候需要指定一個Router對象,以及一個用來創建Logger的LoggerFactory。當這個中間件開始處理請求的時候,它會根據當前HttpContext創建一個RouteContext上下文對象,並將其作為參數調用Router的RotueAsync方法進行路由解析。如果在路由解析結束之後通過RouteContext的Handler屬性返回的請求處理存在,意味著當前請求與注冊的路由匹配,在此情況下它會將當前請求交給這個處理器做後續處理。在這之前它會從RouteContext上下文中提出出RouteData,然後據此創建一個RoutingFeature對象並附加到HttpContext上面。

   1: public class RouterMiddleware
   2: {
   3:     private ILogger             _logger;
   4:     private RequestDelegate     _next;
   5:     private IRouter             _router;
   6:  
   7:     public RouterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IRouter router)
   8:     {
   9:         _next       = next;
  10:         _logger     = loggerFactory.CreateLogger<RouterMiddleware>();
  11:         _router     = router;
  12:     }
  13:  
  14:     public async Task Invoke(HttpContext context)
  15:     {
  16:         RouteContext routeContext = new RouteContext(context);
  17:         routeContext.RouteData.Routers.Add(_router);
  18:         await _router.RouteAsync(routeContext);
  19:         if (null == routeContext.Handler)
  20:         {
  21:             _logger.LogDebug(1, "Request did not match any routes.");
  22:             await _next(context);
  23:         }
  24:         else
  25:         {
  26:             context.Features.Set<IRoutingFeature>(new RoutingFeature {  RouteData = routeContext.RouteData})
  27:             await routeContext.Handler(context);
  28:         }
  29:     }
  30: }

我們除了可以調用HttpContext的擴展方法GetRouteData得到封裝了路由參數的RouteData對象之前,我們還可以調用另一個名為GetRouteValue發的擴展方法直接獲取某個路由參數的值。在如下所示的代碼片段中,我們采用比較簡單代碼展示了這兩個擴展放的實現。

   1: public static class RoutingHttpContextExtensions
   2: {
   3:     public static RouteData GetRouteData(this HttpContext context)
   4:     {
   5:         return context.Features.Get<IRoutingFeature>()?.RouteData;
   6:     }
   7:  
   8:     public static object GetRouteValue(this HttpContext context, string key)
   9:     {
  10:         return context.GetRouteData()?.Values[key];
  11:     }
  12: }

一般來說我們傾向於調用ApplicationBuilder的擴展方法UseRouter來注冊RouterMiddleware中間件。具體來說,我們可以選擇如下兩個UseRouter方法重載。如果調用第一個重載,我們需要為注冊的RouterMiddleware中間件提供一個具體的Router對象。對於第二個重載來說,這個Router對象實際上是利用RouteBuilder創建的,我們在調用這個方法的時候需要以Action<IRouteBuilder>對象的形式利用這個RouteBuilder注冊所需的路由。

   1: public static class RoutingBuilderExtensions
   2: {
   3:     public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, IRouter router)
   4:     {
   5:         return builder.UseMiddleware<RouterMiddleware>(new object[] { router });
   6:     }
   7:  
   8:     public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, Action<IRouteBuilder> action)
   9:     {       
  10:         RouteBuilder routeBuilder = new RouteBuilder(builder);
  11:         action(routeBuilder);
  12:         return builder.UseRouter(routeBuilder.Build());
  13:     }
  14: }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved