.Net core 2.x基礎學習筆記(2) —— 中間件

来源:https://www.cnblogs.com/banluduxing/archive/2019/04/18/10723130.html
-Advertisement-
Play Games

這個系列的初衷是便於自己總結與回顧,把筆記本上面的東西轉移到這裡,態度不由得謹慎許多,下麵是我參考的資源: ASP.NET Core 中文文檔目錄 官方文檔 記在這裡的東西我會不斷的完善豐滿,對於文章裡面一些局限於我自己知識積累的觀點,希望沒有跳走堅持看完的朋友,能夠予以指正和鼓勵. 這個系列的初衷 ...


這個系列的初衷是便於自己總結與回顧,把筆記本上面的東西轉移到這裡,態度不由得謹慎許多,下麵是我參考的資源:

 ASP.NET Core 中文文檔目錄

官方文檔

記在這裡的東西我會不斷的完善豐滿,對於文章裡面一些局限於我自己知識積累的觀點,希望沒有跳走堅持看完的朋友,能夠予以指正和鼓勵.

 

系列目錄

(1)Starup

(2)中間件

 

 

 

中間件

中間件是一種裝配到應用管道以處理請求和響應的軟體。 每個組件:

  • 選擇是否將請求傳遞到管道中的下一個組件
  • 可在管道中的下一個組件前後執行工作

請求委托用於生成請求管道。 請求委托處理每個 HTTP 請求。

請求委托通過使用 IApplicationBuilder 類型的 Run、Map 以及 Use 擴展方法來配置,併在Starup類中傳給configure方法 。每個單獨的請求委托都可以被指定為一個 內嵌匿名方法,或其定義在一個可重用的類中。這些可重用的類被稱作中間件或中間件組件。每個位於請求管道內的中間件組件負責調用管道中下一個組件,或適時短路調用鏈。

 

使用 IApplicationBuilder 創建中間件管道

ASP.NET Core 請求管道包含一系列請求委托,依次調用

 

這系列委托並不是一條路走到底:每個委托均可在下一個委托前後執行操作,使得請求管道短路.

短路的方式存在兩種:

      1任何委托都能選擇停止傳遞到下一個委托,轉而自己處理該請求。這被叫做請求管道的短路

 1   public void Configure(IApplicationBuilder app)
 2   {
 3        //只會列印"Hello, World!",下麵的已經被短路
 4       app.Run(async context =>
 5       {
 6           await context.Response.WriteAsync("Hello, World!");
 7       });
 8   
 9       app.Run(async context =>
10       {
11          await context.Response.WriteAsync("Hello, World, Again!");
12       });
13    }

 所以,最簡單的 ASP.NET 應用程式只需要單個請求委托來處理所有請求即可。而在這種情況下並不存在所謂的“管道”,調用單個匿名函數以響應每個 HTTP 請求

 

       2委托可以不將請求傳遞給下一個委托時,它被稱為“讓請求管道短路”。

 1      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 2         {
 3             var logger = loggerFactory.CreateLogger("");
 4             app.Use(async (context, next) =>
 5             {
 6                 logger.LogInformation("Handling request.");
 7                 //await next.Invoke(); //next 參數表示管道內下一個委托.註釋則短路
 8             });
 9 
10             app.Run(async (context) =>
11             {
12                 await context.Response.WriteAsync("the page lost");
13             });
14          }

那麼用 Use 將多個請求委托鏈接(參見下麵順序一節示例)在一起時。 就可以通過不調用 next 參數使管道短路。

 

短路的存在是非常有意義的,這樣可以避免不必要的工作。 例如,靜態文件中間件可以處理對靜態文件的請求,並讓管道的其餘部分短路,從而起到終端中間件的作用。 如果

中間件添加到管道中,且位於終止進一步處理的中間件前,它們仍處理next.Invoke 語句後面的代碼。

 

Warnning

響應發送到客戶端後,請勿調用next.Invoke。 響應開始之後,對HttpResponse的更改將拋出異常。

例如,設置響應頭,狀態代碼等更改將會引發異常。在調用next之後寫入響應體:

  1. 可能導致協議違規。 例如,寫入超過content-length所述內容長度。
  2. 可能會破壞響應內容格式。 例如,將HTML頁腳寫入CSS文件。

HttpResponse.HasStarted是一個有用的提示,指示是否已發送響應頭和/或正文已寫入。

 

 順序

你添加中間件組件的順序通常會影響到它們處理請求的順序,然後在響應時則以相反的順序返回。這對應用程式安全、性能和功能很關鍵。

以下為常見應用方案中間件組件順序:

  1. 錯誤處理(同時針對於開發環境和非開發環境)
  2. 靜態文件伺服器
  3. 身份驗證
  4. MVC

對應的代碼如下:

 1 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 2 {
 3     loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 4     loggerFactory.AddDebug();
 5 
 6     if (env.IsDevelopment())
 7     {
 8         app.UseDeveloperExceptionPage();
 9         app.UseDatabaseErrorPage();
10         app.UseBrowserLink();
11     }
12     else
13     {
14         app.UseExceptionHandler("/Home/Error");
15     }
16 
17     app.UseStaticFiles();
18 
19     app.UseIdentity();
20 
21     app.UseMvc(routes =>
22     {
23         routes.MapRoute(
24             name: "default",
25             template: "{controller=Home}/{action=Index}/{id?}");
26     });
27 }

 

上面的代碼中(在非開發環境時):

UseExceptionHandler 是第一個被加入到管道中的中間件,因此將會捕獲之後調用中出現的任何異常。

靜態文件模塊 不提供授權檢查,由它提供的任何文件,包括那些位於wwwroot 下的文件都是公開的可被訪問的。如果你想基於授權來提供這些文件:

  1. 將它們存放在 wwwroot 外面以及任何靜態文件中間件都可訪問得到的目錄。
  2. 利用控制器操作來判斷授權是否允許,如果允許則通過返回 FileResult 來提供它們。

被靜態文件模塊處理的請求會在管道中被短路。如果該請求不是由靜態文件模塊處理,那麼它就會被傳給 Identity 模塊 執行身份驗證。如果未通過身份驗證,則管道將被短路。如果請求的身份驗證沒有失敗,則管道的最後一站是 MVC 框架。

如果修改Configure方法中間件添加的順序,則上述預期的的功能將會發生變

 

Run Use Map

使用 Run、Map 和 Use 配置 HTTP 管道。

Run 方法將會短路管道,所以Run 應該只能在你的管道尾部被調用。並且某些中間件組件可公開在管道末尾運行的 Run[Middleware] 方法

Use用來構建請求管道,例如上面那套常用的請求管道,當然它也可以用來短路,發揮和run一樣的作用,

Map*擴展被用於分支管道,支持基於請求路徑或使用謂詞來進入分支,Map 只接受路徑,並配置單獨的中間件管道的功能。

 

在下例中,任何基於路徑 /maptest 的請求都會被管道中所配置的 HandleMapTest 方法所處理。

 1     private static void HandleMapTest1(IApplicationBuilder app)
 2     {
 3         app.Run(async context =>
 4               {
 5                   await context.Response.WriteAsync("Map Test 1");
 6               });
 7     }
 8     private static void HandleMapTest2(IApplicationBuilder app)
 9     {
10         app.Run(async context =>
11               {
12                   await context.Response.WriteAsync("Map Test 2");
13               });
14     }
15     public void Configure(IApplicationBuilder app)
16     {
17         app.Map("/map1", HandleMapTest1);
18         app.Map("/map2", HandleMapTest2);
19         app.Run(async (context) =>
20             {
21                 await context.Response.WriteAsync("the page lost");
22             });
23     }

 

請求響應結果如下:

請求 響應
localhost:xxxx the page lost
localhost:xxxx/map1 Map Test 1
localhost:xxxx/map2 Map Test 2
localhost:xxxx/map3 the page lost

 

 

 

 

 

 

 

在使用 Map 時,將從 HttpRequest.Path 中刪除匹配的線段,並針對每個請求將該線段追加到HttpRequest.PathBase 。

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

 1         private static void HandleBranch(IApplicationBuilder app)
 2         {
 3             app.Run(async context =>
 4             {
 5                 var branchVer = context.Request.Query["branch"];
 6                 await context.Response.WriteAsync($"Branch used = {branchVer}");
 7             });
 8         }
 9         public void Configure(IApplicationBuilder app)
10         {
11             app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
12             app.Run(async context =>
13             {
14                 await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
15             });
16         }

 

請求響應結果如下:

請求 響應
localhost:xxxx Hello from non-Map delegate.
localhost:xxxx/?branch=master Branch used = master

 

 

 

 

 

Map 支持嵌套,例如:

1             app.Map("/level1", level1App =>
2             {
3                 level1App.Map("/level2a", HandleMapTest1);// /level2a/level2a
4                 level1App.Map("/level2b", HandleMapTest2);// /level2a/level2b
5             });

 

內置中間件

 ASP.NET Core 附帶以下中間件組件。 “順序”列提供備註,以說明中間件在請求處理管道中的放置,以及中間件可能會終止請求處理的條件。 如果中間件讓請求處理管道短路,並阻止下游中間件進一步處理請求,它被稱為“終端中間件”,例如:靜態文件中間件

 

中間件 描述 順序
Authentication 提供身份驗證支持。 在需要 HttpContext.User 之前。OAuth 回調的終端。
Cookie Policy 跟蹤用戶是否同意存儲個人信息,並強制實施 cookie 欄位(如 secure和 SameSite )的最低標準 在發出 cookie 的中間件之前。 示例:身份驗證、會話、MVC (TempData)
CORS 配置跨域資源共用 資源共用。 在使用 CORS 的組件之前。
Exception Handling 處理異常 在生成錯誤的組件之前。
Forwarded Headers 將代理標頭轉發到當前請求 在使用已更新欄位的組件之前。 示例:方案、主機、客戶端 IP、方法。
Health Check 檢查 ASP.NET Core 應用及其依賴項的運行狀況,如檢查資料庫可用性。

如果請求與運行狀況檢查終結點匹
配,則為終端。

HTTP Method Override 允許傳入 POST 請求重寫方法 在使用已更新方法的組件之前。
HTTPS Redirection

將所有 HTTP 請求重定向到
HTTPS(ASP.NET Core 2.1 或更高版
本)。

在使用 URL 的組件之前。
HTTP Strict Transport Security (HSTS)

添加特殊響應標頭的安全增強中間
件(ASP.NET Core 2.1 或更高版本)。

在發送響應之前,修改請求的組件之
後。 示例:轉接頭、URL 重寫。

MVC 用 MVC/Razor Pages 處理請求(ASP.NET Core 2.0 或更高版本)。 如果請求與路由匹配,則為終端。
OWIN 與基於 OWIN 的應用、伺服器和中間件進行互操作。 如果 OWIN 中間件處理完請求,則為終端。
Response Caching 提供對緩存響應的支持。 在需要緩存的組件之前。
Response Compression 提供對壓縮響應的支持。 在需要壓縮的組件之前。
Request Localization 提供本地化支持 在對本地化敏感的組件之前。
Routing 定義和約束請求路由。 用於匹配路由的終端。
Session 提供對管理用戶會話的支持。 在需要會話的組件之前。
Static Files 為提供靜態文件和目錄瀏覽提供支持。 如果請求與文件匹配,則為終端。
URL Rewriting 提供對重寫 URL 和重定向請求的支持。 在使用 URL 的組件之前。
WebSockets 啟用 WebSockets 協議。 在接受 WebSocket 請求所需的組件之前。

 

 

自定義中間件

對於更複雜的請求處理功能,ASP.NET 團隊推薦在自己的類中實現中間件,並暴露 IApplicationBuilder 擴展方法,這樣就能通過 Configure方法來被調用如下是一個自定義中間件實例,它從查詢字元串設置當前請求的Culture:

 1   public class RequestCultureMiddleWare
 2     {
 3         private readonly RequestDelegate _next;
 4         public RequestCultureMiddleWare(RequestDelegate next)
 5         {
 6             _next = next;
 7         }
 8 
 9         public async Task InvokeAsync(HttpContext context)
10         {
11             var cultureQuery = context.Request.Query["culture"];
12             if (!string.IsNullOrWhiteSpace(cultureQuery))
13             {
14                 var culture = new CultureInfo(cultureQuery);
15                 CultureInfo.CurrentCulture = culture;
16                 CultureInfo.CurrentUICulture = culture;
17             }
18             await _next(context);
19         }
20     }

 

通過IApplicationBuilder的擴展方法暴露中間件:

1     public static class RequestMiddleWareExtensions
2     {
3         public static IApplicationBuilder UserRequestCultrue(this IApplicationBuilder builder)
4         {
5             return builder.UseMiddleware<RequestCultureMiddleWare>();
6         }
7 
8     }

 

通過 Startup下Configure 方法調用中間件:

1         public void Configure(IApplicationBuilder app)
2         {
3             app.UseRequestCulture();
4             app.Run(async (context) =>
5             {
6                 await context.Response.WriteAsync(
7                 $"Hello {CultureInfo.CurrentCulture.DisplayName}");
8             });
9         }

 

請求依賴項

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

 1     public class CustomMiddleware
 2     {
 3         private readonly RequestDelegate _next;
 4         public CustomMiddleware(RequestDelegate next)
 5         {
 6             _next = next;
 7         }
 8         // IMyScopedService is injected into Invoke
 9         public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
10         {
11             svc.MyProperty = 1000;
12             await _next(httpContext);
13         }
14     }

 

 (終)  

文檔信息

 


感謝您的閱讀,如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕。本文歡迎各位轉載,但是轉載文章之後必須在文章頁面中給出作者和原文連接

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

-Advertisement-
Play Games
更多相關文章
  • 1.導入poi相關jar包 對於只操作2003及以前版本的excel,只需要導入poi-XXX.jar ,如果還需要對2007及以後版本進行操作,則需要導入 poi-ooxml-XXX.jar poi-ooxml-schemas-XXX.jar Maven方式 2.讀取excel文件 ImportE ...
  • 1、官網下載JDK包 2、解壓包 3、打開vi /etc/profile文件添加一下內容 4、java-version查看版本出現如圖內容說明安裝成功 ...
  • 實現添加員工時對工號進行自增長 思路:後臺獲取資料庫中最後一條員工數據的工號,對其進行自增再傳入前端 mybatis映射文件:獲取最後一條數據 ...
  • ASP.NET Core開發者路線圖RoadMap 來源: "MoienTajik/AspNetCore Developer Roadmap" . [toc] 2019年 "ASP.NET Core" 開發者指南: 你可以在下麵找到一張圖,該圖展示了你可以選取的路徑及你想學習的庫,從而成為一名 AS ...
  • 本文對應的原文來至 c sharpcorner 的一篇文章,文末有鏈接。如有錯誤,還請指正。 前言 你會為你的下一個應用程式選擇哪一種開發平臺 .NET Framework 或者 .NET Core?在這篇文章中,讓我們比較一下這兩個開發平臺的特點,看能否得出一個結論。 .NET Framework ...
  • 背景 1. 都2019年了,還在用WinForm嗎?哈哈,其實我也沒在用,都是很多年前一些項目積累,所以代碼寫的有些屎,之所以開源出來,希望能給大家有所幫助,喜歡的話給 一個Star以資鼓勵~; 2. 具體代碼: "MasterChief" 3. 歡迎Star,歡迎Issues; 控制項列表 由於比較 ...
  • 索引: 目錄索引 一.API 列表 1.WhereSegment 屬性,指示 根據條件 動態拼接 where 查詢過濾條件 見如下示例. 二.API 單表-完整 方法 舉例 以 MySQL 為例,生成 SQL 如下,其中 ?Name_2 的值自動生成為 【伏%】 : 三.API 多表-連接 方法 舉 ...
  • 背景 1. 在開發中,我們會碰到諸如String類型轉換為Int等等問題,雖然處理起來簡單,但是本著DRY(Don't Repeat Yourself )原則,還是有必要封裝處理下; 2. 具體代碼: "MasterChief" 3. Nuget:Install Package MasterChie ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...