asp.net core 系列 15 中間件

来源:https://www.cnblogs.com/MrHSR/archive/2019/01/24/10307795.html
-Advertisement-
Play Games

一.概述 中間件(也叫中間件組件)是一種裝配到應用管道以處理請求和響應的軟體。 每個組件:(1)選擇是否將請求傳遞到管道中的下一個組件;(2)可以在管道中的下一個組件之前和之後執行工作。 請求委托用於生成請求管道。 請求委托會處理每個 HTTP 請求。使用以下方法配置請求委托:Run, Map, U ...


一.概述

  中間件(也叫中間件組件)是一種裝配到應用管道以處理請求和響應的軟體。 每個組件:(1)選擇是否將請求傳遞到管道中的下一個組件;(2)可以在管道中的下一個組件之前和之後執行工作。

  請求委托用於生成請求管道。 請求委托會處理每個 HTTP 請求。使用以下方法配置請求委托:Run,  Map, Use擴展方法。可以將單個請求委托作為匿名方法(稱為內聯中間件in-line middleware) 或者可以在可重用類中定義。這些可重用的類和內聯匿名方法是中間件,也稱為中間件組件。請求管道中的每個中間件組件負責調用管道中的下一個組件,或使管道短路。

  (1) Run

      //將終端中間件委托添加到應用程式的請求管道中。
      public static class RunExtensions
      {
          public static void Run(this IApplicationBuilder app, RequestDelegate handler);
      }

   (2) Map

      // 根據給定請求路徑的匹配對請求管道進行分支。
      public static class MapExtensions
      {
          public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);
      }

  (3) Use

      // 提供配置應用程式請求的機制    
      public interface IApplicationBuilder
      {
          //....
          // 將中間件委托添加到應用程式的請求管道中。
          IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); 
      }

 

  1.1 使用 IApplicationBuilder 創建中間件管道

    在Startup. Configure方法中,使用IApplicationBuilder來創建中間件管理。每一個use開頭的擴展方法將一個中間件添加到IApplicationBuilder請求管道中。使用Use擴展方法來配置請求委托。每個use的中間件類似如下聲明:

    public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app )
      public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app , Action<T>)

    ASP.NET Core 請求管道包含一系列請求委托,依次調用。 下圖演示了這一概念。 沿黑色箭頭執行。

         在Startup. Configure代碼中,一系列use請求委托中間件如下所示:

           app.UseHttpsRedirection();
           app.UseStaticFiles();
           app.UseCookiePolicy();
           app.UseMvc();

    委托可以決定不將請求傳遞給下一個委托(中間件),這就是對請求管道進行短路。通常需要短路,因為這樣可以避免不必要的工作。

    下麵示例 是一個最簡單的 ASP.NET core 應用程式,用run方法配置請求委托,設置單個委托處理處理所有請求。此案例不包括實際的請求管道。相反,調用單個匿名函數以響應每個 HTTP 請求。並用委托終止了管道。

    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello, World!");
            });
        }
    }

    下麵示例用Use方法將多個請求委托鏈接在一起,next 參數表示管道中的下一個委托。 可通過不調用 next 參數使管道短路。

            app.Use(async (context, next) =>
            {
              //調用下一個委托(app.run)
                await next.Invoke();
            });

            app.Run(async context =>
            { 
                await context.Response.WriteAsync("Hello, World!");
            });

    

  1.2 中間件順序

     向 Startup.Configure 方法添加中間件組件的順序定義了針對請求調用這些組件的順序,以及響應的相反順序。 此排序對於安全性、性能和功能至關重要。以下 Startup.Configure 方法將為常見應用方案添加中間件組件:  

         (1) 異常/錯誤處理

         (2) HTTP 嚴格傳輸安全協議

         (3) HTTPS 重定向

         (4) 靜態文件伺服器

         (5) Cookie 策略實施

         (6) 身份驗證

         (7) 會話

         (8) MVC

public void Configure(IApplicationBuilder app)
{
    if (env.IsDevelopment())
    {
        // When the app runs in the Development environment:
        //   Use the Developer Exception Page to report app runtime errors.
        //   Use the Database Error Page to report database runtime errors.
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        // When the app doesn't run in the Development environment:
        //   Enable the Exception Handler Middleware to catch exceptions
        //     thrown in the following middlewares.
        //   Use the HTTP Strict Transport Security Protocol (HSTS)
        //     Middleware.
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    // Use HTTPS Redirection Middleware to redirect HTTP requests to HTTPS.
    app.UseHttpsRedirection();

    // Return static files and end the pipeline.
    app.UseStaticFiles();

    // Use Cookie Policy Middleware to conform to EU General Data 
    // Protection Regulation (GDPR) regulations.
    app.UseCookiePolicy();

    // Authenticate before the user accesses secure resources.
    app.UseAuthentication();

    // If the app uses session state, call Session Middleware after Cookie 
    // Policy Middleware and before MVC Middleware.
    app.UseSession();

    // Add MVC to the request pipeline.
    app.UseMvc();
}

    (1) UseExceptionHandler 是添加到管道的第一個中間件組件。 該異常處理程式中間件可捕獲稍後調用中發生的任何異常。

    (2) UseStaticFiles 靜態文件中間件,應該在管道的早期調用。這樣它就可以處理請求和短路,而不需要遍歷其餘組件。靜態文件中間件不提供授權檢查。 它提供的任何文件,包括wwwroot下的文件,都是公開可訪問的。

    (3) UseAuthentication 身份驗證中間件。未經身份驗證的請求不會短路,但只有在特定的Razor頁面或MVC控制器操作之後,才會發生授權(和拒絕)。

 

  1.3  Use、Run 和 Map

     配置 HTTP 管道可以使用Use、Run 和 Map,但各方法針對構建的中間件作用不同:

      (1) Use[Middleware]中間件負責調用管道中的下一個中間件,也可使管道短路(即不調用 next 請求委托)。

      (2) Run[Middleware]是一種約定,一些中間件組件可能會公開在管道末端運行的Run[Middleware]方法。

      (3) Map擴展用作約定來創建管道分支, Map*創建請求管道分支是基於給定請求路徑的匹配項。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Map("/Map1",HandleMapTest1);
            app.Map("/Map2", HandleMapTest2);
            //其它請求地址
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
            });
        }

        private static void HandleMapTest1(IApplicationBuilder app)
        {
             app.Run(async context =>
            {
                await context.Response.WriteAsync("Map Test 1");
            });
        }

        private static void HandleMapTest2(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Map Test 2");
            });
        }

    Map  還支持嵌套,下麵的示例中,請求訪問/level1/level2a 和 /level1/level2b時進行不同邏輯處理:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

     

  1.4 MapWhen

    MapWhen 基於url給定謂詞的結果創建請求管道分支。 Func<HttpContext, bool> 類型的任何謂詞均可用於將請求映射到管道的新分支。 在以下示例中,謂詞用於檢測查詢字元串變數 branch 是否存在,如果存在使用新分支(HandleBranch)。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration
            app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
           
            //非匹配branch其它請求地址
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
            });
        }

        private static void HandleBranch(IApplicationBuilder app)
        {
             app.Run(async context =>
            {
                var branchVer = context.Request.Query["branch"];
                await context.Response.WriteAsync("Map Test 1");
            });
        }

 

二. 編寫中間件    

  上面演示在請求管道中使用use,map,run方法,來委托處理每個 HTTP 請求就是中間件。通常中間件會封裝在類中,並且通過擴展方法公開。下麵示例是如何編寫一個中間件組件。處理邏輯是該中間件通過查詢字元串設置當前請求的區域性。

    /// <summary>
    /// 自定義中間件實現類
    /// </summary>
    public class RequestCultureMiddleware
    {
        //using Microsoft.AspNetCore.Http
        private readonly RequestDelegate _next;

      
      /// <summary>
      /// 程式啟動時調用
      /// </summary>
      /// <param name="next"></param>
    public RequestCultureMiddleware(RequestDelegate next)
        {
            this._next = next;
        }

    
      /// <summary>
      ///每個頁面請求時自動調用,方法按約定命名,必需是Invoke或InvokeAsync
      /// </summary>
      /// <param name="context"></param>
      /// <returns></returns>
    public async Task InvokeAsync(HttpContext context)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                //using System.Globalization;
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;

            }
            // Call the next delegate/middleware in the pipeline
            await _next(context);
        }
    }

    /// <summary>
    /// 通過擴展方法公開中間件 
    /// </summary>
    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder)
        {
            //在管道中添加一個use的中間件
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
        public void Configure(IApplicationBuilder app)
        {
            //調用中間件
            app.UseRequestCulture();

            app.Run(async (context) =>
            {
                await ResponseAsync(context);
            });

        }

        private  async  Task ResponseAsync(HttpContext context)
        {
            context.Response.ContentType = "text/html; charset=utf-8";
            await context.Response.WriteAsync(
                    //列印當前顯示的語言
                    $"Hello { CultureInfo.CurrentCulture.DisplayName }"
                    );
        }

  2.1 請求依賴項

    由於中間件是在應用啟動時構造的(實例),而不是在每個請求時的,因此在每個請求過程中,中間件構造函數使用的作用域生命周期服務,不會在每個請求期間與其他依賴註入類型共用。如果必須在中間件和其他類型之間共用一個範圍服務,請將這些服務添加到 Invoke 方法的簽名。 Invoke 方法可接受由 DI 填充的參數

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // IMyScopedService is injected into Invoke
    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        svc.MyProperty = 1000;
        await _next(httpContext);
    }
}

 

  參考文獻:

    官方文檔:ASP.NET Core 中間件

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 一.Exceptionless簡介 Exceptionless 是一個開源的實時的日誌收集框架,它可以應用在基於 ASP.NET,ASP.NET Core,Web Api,Web Forms,WPF,Console,MVC 等技術棧的應用程式中,並且提供了Rest介面可以應用在 Javascript ...
  • c#行轉列 今天工作中,恰好寫到此處,想起之前第一次行轉列的時候,卡殼了好久,今天正好碰上,故而花費幾分鐘,整理成案例,分享到博客上。 這是個很簡單的功能,第一次可以使用案例,後面最好能達到信手拈來的地步。 開發要素第一步: 各種控制項的命名要改:這個跟技術能力無關,工作再趕再忙,這個也必須要改,因為 ...
  • nginx反向代理後abp的webapi host如何獲取客戶端ip ...
  • 騰訊雲通信後臺生成usersig只有java實現代碼。以下是根據java代碼轉換為net實現,java版GitHub地址:https://github.com/TencentVideoCloudMLVBDev/usersig_server_source/blob/master/java/WebRTC ...
  • sn.exe 和ilasm.exe 是系統自帶程式。如果顯示無此命令,可以從“我的電腦”直接搜索。將dll文件放入目錄下,用VS開發人員命令執行以下命令即可。(以Interop.Scripting.dll為例)1.創建一個新的隨機密鑰對:sn -k Interop.Scripting.snk2.反編 ...
  • ASP.NET Core 可以用作傳統的web服務、RESTful服務、遠程過程調用(RPC)服務、微服務,這歸功於它的跨平臺支持和輕量級設計 ...
  • CultureInfo類位於System.Globalization命名空間內,這個類和命名空間許多人都不是很熟悉,實際我們在寫程式寫都經常間接性的接觸這個類,當進行數字,日期時間,字元串匹配時,都會進行CultureInfo的操作,也就是說,也就是不同的CultureInfo下,這些操作的結果可能 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...