日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ASP.NET CORE 管道模型及中間件使用解讀

 小世界的野孩子 2021-04-13

說到ASP.NET CORE 管道模型不得不先來看看之前的ASP.NET 的管道模型,兩者差異很大,.NET CORE 3.1 后完全重新設(shè)計(jì)了框架的底層,.net core 3.1 的管道模型更加靈活便捷,可做到熱插拔,通過管道可以隨意注冊自己想要的服務(wù)或者第三方服務(wù)插件.

ASP.NET 管道

ASP.NET 管道模型.png

請求進(jìn)入ASP.NET 工作進(jìn)程后,由進(jìn)程創(chuàng)建HttpWorkRequest 對象,封裝此次請求有關(guān)的所有信息,然后進(jìn)入HttpRuntime 類進(jìn)行進(jìn)一步的處理。HttpRuntime 通過請求信息創(chuàng)建HttpContext 上下文對象,此對象將貫穿整個(gè)管道,直到響應(yīng)結(jié)束。同時(shí)創(chuàng)建或從應(yīng)用程序池里初始化一個(gè)HttpApplication對象,由此對象開始處理之前注冊的多個(gè)HttpModule。之后調(diào)用HandlerFactory 創(chuàng)建Handler處理程序,最終處理此次請求內(nèi)容,生存響應(yīng)返回。

以前的管道模型是全家桶方式,所有的管道不支持熱插拔,一次性全部集成在里面,所有這也是ASP.NET 沒有.NET CORE 性能好的一大原因所在。

.NET CORE管道模型.png

IHttpModule 和IHttpHandler 已經(jīng)不復(fù)存在了,取而代之的是一個(gè)個(gè)中間件(Middleware)。Server將接收到的請求直接向后傳遞,依次經(jīng)過每一個(gè)中間件進(jìn)行處理,然后由最后一個(gè)中間件處理并生成響應(yīng)內(nèi)容后回傳,再反向以此經(jīng)過每個(gè)中間件,直到由Server發(fā)送出去。中間件就像一層一層的“濾網(wǎng)”,過濾所有的請求和響應(yīng)。這一設(shè)計(jì)非常適用于“請求-響應(yīng)”這樣的場景--消息從管道頭流入最后反向流出。

ASP.NET Core是一套全新的平臺,已經(jīng)不再向前兼容,設(shè)計(jì)更追求組件化,追求高性能,沒有全家桶,那么ASP.NET Core是怎么搭建請求管道的呢?默認(rèn)情況,管道只有一個(gè)404。然后你也可以增加請求的處理,這就是以前的Handler,只包含業(yè)務(wù)處理環(huán)節(jié),其他的就是中間件,MiddleWare。

我們現(xiàn)在來看下幾種中間件注冊的模式:

以下的代碼都把Configure 中的代碼全部注釋的情況下從零代碼開始一個(gè)一個(gè)注冊演示

  • 終結(jié)者模式
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 { 
     Console.WriteLine("Configure");   
     app.Run(async (HttpContext context) => { 
             await context.Response.WriteAsync("Hello World Run");
      });
     app.Run(async (HttpContext context) => { 
            await context.Response.WriteAsync("Hello World Run Again"); 
     }); 
}

運(yùn)行代碼后瀏覽器可以看到結(jié)果如下:

3.png

從上面的運(yùn)行結(jié)果可以看出 Run 終結(jié)式 只是執(zhí)行,沒有去調(diào)用Next ,一般作為終結(jié)點(diǎn)。所謂Run終結(jié)式注冊,其實(shí)只是一個(gè)擴(kuò)展方法,最終還不是得調(diào)用Use方法,

  • Use 方式注冊

代碼如下:

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Hello World Use1 <br/>");
                await next();//調(diào)用下一個(gè)中間件
                await context.Response.WriteAsync("Hello World Use1 End <br/>");
            });
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Hello World Use2 Again <br/>");
                await next();
            });
  }

以上代碼得出的結(jié)果如下:

Hello World Use1
Hello World Use2 Again

從運(yùn)行結(jié)果 中hello world use 1 end
并未執(zhí)行,主要是在它上面 next() 調(diào)用了下一個(gè)中間件,到那里已經(jīng)終結(jié)到下一個(gè)中間件執(zhí)行去了。

再來看下面的代碼運(yùn)行結(jié)果:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Hello World Use1 <br/>");
            });
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Hello World Use2  <br/>");
            });
 }

結(jié)果如圖:

結(jié)果.png

第二個(gè)中間件也并未得到執(zhí)行,use 方式注冊中間件得出的結(jié)論是:Use注冊動作 不是終結(jié)點(diǎn) ,執(zhí)行next,就可以執(zhí)行下一個(gè)中間件 如果不執(zhí)行,就等于Run

  • UseWhen可以對HttpContext檢測后,增加處理環(huán)節(jié);原來的流程還是正常執(zhí)行的,代碼如下 該方式注冊可以實(shí)現(xiàn)一系列的驗(yàn)證攔截等操作,從管道的上一層管道進(jìn)行合理性攔截匹配等等系列過濾,可以說類似于Filter 的實(shí)現(xiàn)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
            app.UseWhen(context =>
            {
              
               return context.Request.Query.ContainsKey("Name");
            },
            appBuilder =>
             {
                 appBuilder.Use(async (context, next) =>
                 {
                     await context.Response.WriteAsync("Hello World Use3 Again Again Again <br/>");
                     await next();
                 });
            });
 }

看了上面的幾個(gè)管道應(yīng)用模塊的注冊,我們再來一起解讀下源代碼

IApplicationBuilder 應(yīng)用程序的組裝者,RequestDelegate:傳遞一個(gè)HttpContext,異步操作下,不返回;也就是一個(gè)處理動作,Use(Func<RequestDelegate, RequestDelegate> middleware) 委托,傳入一個(gè)RequestDelegate,返回一個(gè)RequestDelegate。ApplicationBuilder里面有個(gè)容器IList<Func<RequestDelegate, RequestDelegate>> _components,Use就只是去容器里面添加個(gè)元素。最終會Build()一下, 如果沒有任何注冊,就直接404處理。

核心代碼如下:

public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
     _components.Add(middleware);
     return this;
}

 public RequestDelegate Build()
 {
            RequestDelegate app = context =>
            {
                // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
                // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
                var endpoint = context.GetEndpoint();
                var endpointRequestDelegate = endpoint?.RequestDelegate;
                if (endpointRequestDelegate != null)
                {
                    var message =
                        $"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
                        $"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
                        $"routing.";
                    throw new InvalidOperationException(message);
                }

                context.Response.StatusCode = 404;
                return Task.CompletedTask;
            };

            foreach (var component in _components.Reverse())
            {
                app = component(app);
            }

            return app;
 }

IApplicationBuilder build之后其實(shí)就是一個(gè)RequestDelegate,能對HttpContext加以處理,默認(rèn)情況下,管道是空的,就是404;可以根據(jù)你的訴求,任意的配置執(zhí)行,一切全部由開發(fā)者自由定制,框架只是提供了一個(gè)組裝方式

看了源代碼后我們再來對上面的中間件進(jìn)行優(yōu)雅的封裝,封裝后的代碼如下:

public class FirstMiddleWare
    {
        private readonly RequestDelegate _next;

        public FirstMiddleWare(RequestDelegate next)
        {
            this._next = next;
        }


        public async Task Invoke(HttpContext context)
        {
            await context.Response.WriteAsync($"{nameof(FirstMiddleWare)},Hello World1!<br/>");

            await _next(context);

            await context.Response.WriteAsync($"{nameof(FirstMiddleWare)},Hello World2!<br/>");
        }
    }

使用注冊中間件

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
      app.UseMiddleware<FirstMiddleWare>();
 }

我們可以再升級一點(diǎn)點(diǎn),使用擴(kuò)展方法,將這個(gè)類中的邏輯作為IApplicationBuilder的擴(kuò)展方法。

public static class MiddleExtend
{
    public static IApplicationBuilder UseFirstMiddleWare(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FirstMiddleWare>();
    }
}

使用時(shí)代碼如下:

app.UseFirstMiddleWare();

到這里.net core 管道模型和中間件注冊使用已經(jīng)告一段落了,后續(xù)我們繼續(xù)來分享.net core 中的過濾器使用

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多