程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 學習ASP.NET Core, 怎能不了解請求處理管道[5]: 中間件注冊可以除了可以使用Startup之外,還可以選擇StartupFilter,

學習ASP.NET Core, 怎能不了解請求處理管道[5]: 中間件注冊可以除了可以使用Startup之外,還可以選擇StartupFilter,

編輯:關於.NET

學習ASP.NET Core, 怎能不了解請求處理管道[5]: 中間件注冊可以除了可以使用Startup之外,還可以選擇StartupFilter,


中間件的注冊除了可以借助Startup對象(DelegateStartup或者ConventionBasedStartup)來完成之外,也可以利用另一個叫做StartupFilter的對象來實現。所謂的StartupFilter是對所有實現了IStartupFilter接口的類型及其對象的統稱。IStartupFilter接口定義了如下一個唯一的方法Configure,該方法的參數next返回的Action<IApplicationBuilder>對象體現了後續StartupFilter和Startup對中間件的注冊,而自身對中間件的注冊則實現在返回的Action<IApplicationBuilder>對象中。[本文已經同步到《ASP.NET Core框架揭秘》之中]

   1: public interface IStartupFilter
   2: {
   3:     Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
   4: }

我們可以采用服務注冊的方式注冊多個StartupFilter。具體來說,StartupFilter具有如下兩種不同的注冊方式,一種是通過調用WebHostBuilder的ConfigureServices方法以服務的形式注冊所需的StartupFilter,另一種則是將針對StartupFilter的服務注冊實現在啟動類的ConfigureServices方法上。

   1: //注冊方式1
   2: new WebHostBuilder()
   3:     .ConfigureServices(svcs => svcs
   4:         .AddSingleton<IStartupFilter, Filter1>()
   5:         .AddSingleton<IStartupFilter, Filter2>())                    
   6:     …
   7:  
   8: //注冊方式2
   9: public class Startup
  10: {
  11:     public void ConfigureServices(IServiceCollection svcs)
  12:     {
  13:         svcs.AddSingleton<IStartupFilter,Filter1>()
  14:             .AddSingleton<IStartupFilter, Filter2>();
  15:     }    
  16: }

既然中間件可以同時通過Startup和StartupFilter進行注冊,那麼通過這兩個種方式注冊的中間件有何不同嗎?其實它們唯一的區別在於StartupFilter注冊的中間件會先執行。話句話說,對於由注冊中間件構成的管道來說,通過Startup注冊的中間件位於通過StartupFilter注冊的中間件之後。我們不妨通過一個簡單的實例來證實這一點。我們在一個ASP.NET Core控制台應用中定義如下四個中間件類型(Foo、Bar、Baz和Gux),它們針對請求的處理邏輯很簡單,就是將自身的類型名稱寫入請求的響應中。

   1: public abstract class MiddlewareBase
   2: {
   3:     private RequestDelegate _next;
   4:  
   5:     public MiddlewareBase(RequestDelegate next)
   6:     {
   7:         _next = next;
   8:     }
   9:     public async Task Invoke(HttpContext context)
  10:     {
  11:         await context.Response.WriteAsync($"{this.GetType().Name}=>");
  12:         await _next(context);
  13:     }
  14: }
  15:  
  16: public class Foo : MiddlewareBase
  17: {
  18:     public Foo(RequestDelegate next) : base(next){}
  19: }
  20: public class Bar : MiddlewareBase
  21: {
  22:     public Bar(RequestDelegate next) : base(next) {}
  23: }
  24: public class Baz : MiddlewareBase
  25: {
  26:     public Baz(RequestDelegate next) : base(next) {}
  27: }
  28: public class Gux : MiddlewareBase
  29: {
  30:     public Gux(RequestDelegate next) : base(next) {}
  31: }

接下來我們定義了如下一個泛型的 StartupFilter<TMiddleware>類,這是一個專門用於注冊指定類型中間件的StartupFilter,泛型參數代表注冊的中間件類型。在實現的Configure方法中,我們將中間件的注冊實現在返回的Action<IApplicationBuilder>對象中。

   1: public class StartupFilter<TMiddleware> : IStartupFilter
   2: {
   3:     public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
   4:     {
   5:         return app=> {
   6:             app.UseMiddleware<TMiddleware>();
   7:             next(app);
   8:         };
   9:     }
  10: }

我們最終編寫如下一段簡單的程序來啟動承載的應用程序。如下面的額代碼片段所示,在利用WebHostBuilder創建並啟動WebHost之前,我們調用其ConfigureServices方法注冊了兩個StartupFilter<TMiddleware>對象,它們對應的中間件類型分別為Foo和Bar。在隨後調用的Configure方法中,我們又完成了針對中間Baz和Gux的注冊。這段程序實際上注冊了五個中間件(調用ApplicationBuilder的Run方法可以視為中間件注冊)。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         new WebHostBuilder()
   6:             .UseKestrel()
   7:             .ConfigureServices(svcs => svcs
   8:                 .AddSingleton<IStartupFilter>(new StartupFilter<Foo>())
   9:                 .AddSingleton<IStartupFilter>(new StartupFilter<Bar>()))
  10:             .Configure(app => app
  11:                 .UseMiddleware<Baz>()
  12:                 .UseMiddleware<Gux>()
  13:                 .Run(async context=> await context.Response.WriteAsync("End")))
  14:             .Build()
  15:             .Run();
  16:     }
  17: }

我們現在需要確定注冊的這五個在進行請求處理過程中的執行順序。為此我們直接啟動這個程序,然後開啟浏覽器訪問默認的監聽地址(http://localhost:5000),浏覽器會按照如下圖所示形式顯示出請求在這個五個中間件中的“路由”。浏覽器顯示的結果清晰地表明通過StartupFilter注冊的中間件比通過Startup注冊的中間件先執行。對於兩個采用相同方式注冊的中間件,先被注冊的中間會先執行。

9

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