<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ASP.NET Core Middleware抽絲剝繭

          共 4500字,需瀏覽 9分鐘

           ·

          2021-01-13 21:56

          一. 中間件的概念和數(shù)據(jù)結(jié)構(gòu)

          ASP.NET Core Middleware是在ASP.NET Core處理管道中處理特定業(yè)務(wù)邏輯的組件。

          ASP.NET Core處理管道由一系列請求委托組成,一環(huán)接一環(huán)的調(diào)用特定的中間件。

          上圖示例:
          處理管道包含四個中間件,每個中間件都包含后續(xù)中間件執(zhí)行動作的引用(next),同時每個中間件在交棒之前和交棒之后可以自行參與針對HttpContxt的業(yè)務(wù)處理。

          通過上面的分析,中間件其實具備兩個特征:

          • 入?yún)?/span>:下一個中間件的執(zhí)行委托RequestDelegate ?(public delegate Task RequestDelegate(HttpContext context);)
          • 輸出:特定中間件的業(yè)務(wù)處理動作:因為中間件是處理管道中預設(shè)的處理邏輯,所以這個動作其實也是一個委托RequestDelegate

          所以.NET Core用Func 數(shù)據(jù)結(jié)構(gòu)表示中間件是合理的。

          二. Middleware的定義方式

          ASP.NETCore 提供了很多內(nèi)置的中間件,幫助我們完成基礎(chǔ)通用的業(yè)務(wù)邏輯。

          有兩種自定義中間件的方式:

          1. Factory-based Middleware

          基于工廠模式的中間件有如下優(yōu)點:

          • 在每個客戶端請求時激活實例 (injection of scoped services)
          • 實現(xiàn)IMiddleware接口: 強類型
          //??該接口只有一個固定的函數(shù)
          public?Task?InvokeAsync(HttpContext?context,RequestDelegate?next);
          ??public?class?FactoryActivatedMiddleware?:?IMiddleware
          ????{
          ????????private?readonly?ILogger?_logger;

          ????????public?FactoryActivatedMiddleware(ILoggerFactory?logger)???//?
          ????????{
          ????????????_logger?=?logger.CreateLogger();

          ????????}
          ????????public?async?Task?InvokeAsync(HttpContext?context,?RequestDelegate?next)
          ????????{
          ????????????//?TODO??logic?handler
          ????????????_logger.LogInformation("測試");
          ????????????await?next(context);
          ????????????//?TODO??logic?handler
          ????????}
          ????}

          使用工廠模式的中間件,構(gòu)造函數(shù)參數(shù)由依賴注入(DI)填充;?

          在[使用UseMiddleware()注冊中間件]時不允許顯式傳參。

          源碼在https://github.com/dotnet/aspnetcore/blob/v5.0.1/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs第56行。

          2. Conventional-based Middleware

          顧名思義,基于約定的中間件類有一些特定約定:

          • 具有RequestDelegate類型參數(shù)的公共構(gòu)造函數(shù)
          • 名稱為Invoke或InvokeAsync的公共方法, 此方法必須
            ①返回Task ? ② 方法第一個參數(shù)是HttpContext
          public?class?ConventionalMiddleware
          {
          ????private?readonly?RequestDelegate?_next;

          ????public?ConventionalMiddleware(RequestDelegate?next)
          ????{
          ????????_next?=?next;
          ????}

          ????public?async?Task?InvokeAsync(HttpContext?context,?AppDbContext?db)
          ????{
          ????????var?keyValue?=?context.Request.Query["key"];

          ????????if?(!string.IsNullOrWhiteSpace(keyValue))
          ????????{
          ????????????db.Add(new?Request()
          ????????????????{
          ????????????????????DT?=?DateTime.UtcNow,?
          ????????????????????MiddlewareActivation?=?"ConventionalMiddleware",?
          ????????????????????Value?=?keyValue
          ????????????????});

          ????????????await?db.SaveChangesAsync();
          ????????}

          ????????await?_next(context);
          ????}
          }

          構(gòu)造函數(shù)和Invoke/InvokeAsync的其他參數(shù)由依賴注入(DI)填充;
          基于約定的中間件,在[使用UseMiddleware()注冊中間件]時允許顯式傳參。

          三. 注冊中間件的算法分析

          app.UseMiddleware()內(nèi)部使用app.Use(Func middleware)注冊中間件,
          返回值還是IApplicationBuilder, 故具備鏈式注冊的能力。

          算法類似于基礎(chǔ)鏈表, 只是指針指向的不是節(jié)點,而是后續(xù)節(jié)點的字段。

          //--------節(jié)選自?Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder--------
          private?readonly?IList>?_components?=?new?List>();
          ?

          public?IApplicationBuilder?Use(Func?middleware)
          {
          ????this._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?=?StatusCodes.Status404NotFound;
          ????????????????return?Task.CompletedTask;
          ????????????};

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


          ????????????return?app;
          }?

          通過以上代碼我們可以看出:

          • 注冊中間件的過程實際上,是給一個Type為List> 的集合依次添加元素的過程;

          • 中間件的數(shù)據(jù)結(jié)構(gòu):(input)后置中間件的執(zhí)行函數(shù)指針(以委托RequestDelegate表示),(output)當前中間件的執(zhí)行函數(shù)指針(以委托RequestDelegate表示);

          • 通過build方法將集合打通為鏈表,鏈表就是我們常說的[處理管道]。

          build方法是在web托管服務(wù)GenericWebHostService開始啟動的時候被調(diào)用。源碼在https://github.com/dotnet/aspnetcore/blob/master/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs 105 行。

          附:非標準中間件的用法

          短路中間件、 分叉中間件、條件中間件

          整個處理管道的形成,存在一些管道分叉或者臨時插入中間件的行為,一些重要方法可供使用
          • Use方法是一個注冊中間件的簡便寫法
          • Run方法是一個約定,一些中間件使用Run方法來完成管道的結(jié)尾

          • Map擴展方法:Path滿足指定條件,將會執(zhí)行分叉管道

          • MapWhen方法:HttpContext滿足條件,將會執(zhí)行分叉管道,相比Map有更靈活的匹配功能

          • UseWhen方法:HttpContext滿足條件則插入中間件



          關(guān)注并星標我們
          更多干貨及最佳實踐分享


          瀏覽 114
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷中文字幕9 | 亚洲新人天堂中文 | 日韩一级a | 日日操夜夜操狠狠操 | 97在线观看视频 |