柚子快報(bào)邀請(qǐng)碼778899分享:3. 中間件的最佳方法
柚子快報(bào)邀請(qǐng)碼778899分享:3. 中間件的最佳方法
中間件是 ASP.NET Core 中最強(qiáng)大的概念之一。對(duì)于傳統(tǒng)的 ASP.NET 開(kāi)發(fā)人員來(lái)說(shuō),“中間件”是一個(gè)相對(duì)較新的術(shù)語(yǔ)。在中間件出現(xiàn)之前,存在 HTTP 處理程序和模塊,需要通過(guò) web.config 進(jìn)行單獨(dú)的代碼配置?,F(xiàn)在,中間件被視為 ASP.NET 應(yīng)用程序中的一等公民,使其更易于在單個(gè)代碼庫(kù)中維護(hù)。通用請(qǐng)求和響應(yīng)概念首次在 ASP.NET Core 1.0 中引入,被視為應(yīng)用程序的管道,能夠控制請(qǐng)求和響應(yīng)的主體。這為創(chuàng)建 ASP.NET Core Web 應(yīng)用程序的驚人功能開(kāi)辟了許多可能性。
在本章的開(kāi)頭,我們將研究如何使用中間件以及幾乎每個(gè) ASP.NET Core 應(yīng)用程序中的一些常見(jiàn)內(nèi)置中間件組件。接下來(lái),我們將研究三個(gè)請(qǐng)求委托(Run、Map 和 Use),并解釋每個(gè)委托在管道中的用途。我們還將介紹一些清理中間件的方法,并最終將這些概念應(yīng)用于構(gòu)建一個(gè)簡(jiǎn)單的中間件示例。
在本章中,我們將介紹以下主要主題:
使用中間件中間件的常見(jiàn)做法創(chuàng)建表情符號(hào)中間件組件
在本章結(jié)束時(shí),您將理解中間件的工作原理、編寫(xiě)自己的中間件時(shí)如何使用請(qǐng)求委托和標(biāo)準(zhǔn),并理解如何創(chuàng)建自己的中間件組件。
技術(shù)要求
由于這是包含技術(shù)要求的第一章(由于我們現(xiàn)在處于編碼領(lǐng)域,因此接下來(lái)還有許多章),因此選擇支持 ASP.NET Core 7.0 或更高版本和 C# 代碼的最喜歡的編輯器將是理想的選擇。我最喜歡的三個(gè)編輯器如下:
Visual Studio(最好是 2022 或更新版本)Visual Studio CodeJetBrains Rider
我們將使用的編輯器是 Visual Studio 2022 Enterprise,但任何版本(社區(qū)版或?qū)I(yè)版)都適用于本章。
本章的代碼位于 Packt Publishing 的 GitHub 存儲(chǔ)庫(kù)中:https://github.com/PacktPublishing/ASP.NET-Core-8-Best-Practices。
使用中間件
中間件是應(yīng)用程序啟動(dòng)時(shí)在應(yīng)用程序開(kāi)始時(shí)配置的軟件。需要注意的是,您添加的中間件應(yīng)基于應(yīng)用程序的要求。沒(méi)有必要添加每個(gè)組件。簡(jiǎn)化中間件管道很重要,我們將很快討論這一點(diǎn)。
有人說(shuō),庫(kù)和框架之間的區(qū)別在于,庫(kù)是您從應(yīng)用程序調(diào)用的代碼,而框架則以某種方式構(gòu)造來(lái)調(diào)用您的代碼。這就是中間件從早期版本的 ASP.NET 發(fā)展而來(lái)的樣子。
在本節(jié)中,我們將介紹中間件管道的常見(jiàn)流程以及如何控制中間件組件中發(fā)生的事情。在本節(jié)結(jié)束時(shí),您將理解中間件管道的工作原理。
理解中間件管道
當(dāng)您的 Web 應(yīng)用程序啟動(dòng)時(shí),中間件在每個(gè)應(yīng)用程序生命周期中被調(diào)用和構(gòu)建一次。一旦中間件組件被注冊(cè),它們就會(huì)按特定順序執(zhí)行。這個(gè)順序在整個(gè)管道中都很重要,因?yàn)槊總€(gè)中間件組件都可以依賴先前注冊(cè)的組件。
例如,在配置授權(quán)組件之前,身份驗(yàn)證組件很重要,因?yàn)槲覀冃枰戎滥橙耸钦l(shuí),然后才能確定他們可以做什么。
在圖 3.1 中,我們可以看到 Web 應(yīng)用程序中標(biāo)準(zhǔn)中間件管道的組成,接下來(lái)我們將介紹:
圖 3.1 – ASP.NET 8 Web 應(yīng)用程序的標(biāo)準(zhǔn)中間件管道
這些組件中的每一個(gè)都是可選的,但一些中間件組件依賴于其他組件。當(dāng)用戶請(qǐng)求 URL 時(shí),第一個(gè)中間件組件被命中。在本例中,它是 ExceptionHandler。一旦 ExceptionHandler 完成,管道就會(huì)轉(zhuǎn)到下一個(gè)組件,即 HSTS 組件。當(dāng)我們移動(dòng)每個(gè)中間件組件時(shí),我們最終到達(dá)端點(diǎn)。處理完端點(diǎn)后,響應(yīng)將以相反的順序通過(guò)中間件管道發(fā)回。
正如本節(jié)開(kāi)頭所述,您的中間件取決于您的應(yīng)用程序在添加其他組件時(shí)需要什么。如果您的應(yīng)用程序是單頁(yè)應(yīng)用程序 (SPA),則包含 CORS、靜態(tài)文件和路由中間件將非常重要。
每個(gè)中間件組件負(fù)責(zé)根據(jù)您的配置將信息傳遞給下一個(gè)組件或終止該過(guò)程。如果它們決定終止管道,則它們被稱為終端中間件組件。它們會(huì)故意阻止中間件處理任何其他請(qǐng)求并退出管道。
使用請(qǐng)求委托 - 運(yùn)行、使用和映射
通過(guò)我們到目前為止討論的所有內(nèi)容,您可能想知道我們?nèi)绾蝿?chuàng)建管道。
可用的三個(gè)請(qǐng)求委托是Run、Use和Map擴(kuò)展方法。您無(wú)疑在Program.cs代碼中多次使用它們,但這三個(gè)之間有什么區(qū)別?
Run
Run()請(qǐng)求委托是嚴(yán)格的終端中間件,這意味著它將運(yùn)行并立即退出管道。它不包含next參數(shù)。它只是運(yùn)行并立即終止管道。
如果我們查看以下代碼,這將立即終止管道的執(zhí)行:
app.Run(async context =>
{
await context.Response.WriteAsync("This will terminate the web app.");
});
請(qǐng)注意,委托中沒(méi)有引入 next 參數(shù)。上述代碼將向?yàn)g覽器寫(xiě)入消息 “這將終止 Web 應(yīng)用程序。”,并立即終止管道。
Use
Use() 請(qǐng)求委托用于在管道中將多個(gè)請(qǐng)求委托鏈接在一起。
實(shí)現(xiàn)正確的 Use 請(qǐng)求委托的關(guān)鍵是使用 await next.Invoke()。next.Invoke() 將按順序執(zhí)行下一個(gè)中間件組件。此行之前的任何內(nèi)容都將在請(qǐng)求中處理,此行之后的任何內(nèi)容都將在返回給用戶的響應(yīng)中處理。
讓我們看看以下代碼片段中兩個(gè)匿名中間件組件的代碼示例:
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("In the first middleware call.\ r\n");
await context.Response.WriteAsync("Executing the next Middleware...\r\n");
await next();
await context.Response.WriteAsync("In the first middleware call…on the return trip.\r\n");
});
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("We're in the second middleware call\r\n");
await next();
await context.Response.WriteAsync("On our way back from the second middleware call\r\n");
});
此代碼創(chuàng)建以下輸出:
In the first middleware call.
Executing the next Middleware...
We're in the second middleware call
On our way back from the second middleware call
In the first middleware call…on the return trip.
您會(huì)注意到在執(zhí)行 next.invoke() 代碼行之前發(fā)生的任何情況,然后執(zhí)行將按順序轉(zhuǎn)到下一個(gè)中間件。一旦我們到達(dá)中間件管道的末尾,我們就會(huì)返回,在每個(gè)中間件的 await next(); 語(yǔ)句之后執(zhí)行所有代碼。
執(zhí)行每個(gè)中間件組件后,應(yīng)用程序?qū)⑦\(yùn)行,然后按相反順序返回。
Map
Map() 請(qǐng)求委托用于根據(jù)特定請(qǐng)求路徑或路由對(duì)管道進(jìn)行分支。雖然這是針對(duì)特定中間件條件的,但創(chuàng)建新映射的可能性極小。通常最好使用預(yù)構(gòu)建的中間件組件,例如 .MapRazorPages()、.MapControllers() 或任何其他 .MapXxxx() 方法。這些方法已經(jīng)具有預(yù)定義的路由。大多數(shù)路由發(fā)生在其他擴(kuò)展中,例如前面提到的中間件方法。
還有一個(gè) MapWhen() 擴(kuò)展方法,用于根據(jù)給定謂詞的結(jié)果進(jìn)行條件中間件分支。例如,如果您想為您的網(wǎng)站創(chuàng)建一個(gè)受控的維護(hù)頁(yè)面,您可以使用一個(gè)名為 underMaintenance 的簡(jiǎn)單布爾值,并使用它來(lái)顯示一條簡(jiǎn)單消息,直到您的網(wǎng)站再次可用:
app.MapWhen(_ => underMaintenance, ctx =>
ctx.Run(async context =>
{
await context.Response
.WriteAsync("We are currently under maintenance.");
})
);
在前面的代碼中,我們添加了 .MapWhen() 委托,以使用特定的布爾值來(lái)標(biāo)識(shí)我們是否處于維護(hù)狀態(tài)。請(qǐng)注意,我們使用 .Run 委托,因?yàn)槲覀儾幌肜^續(xù)執(zhí)行中間件管道。這種方法只是中間件靈活性的一個(gè)例子。
使用內(nèi)置中間件組件
雖然您可以創(chuàng)建自己的中間件組件,但最好的方法是從大量現(xiàn)有的內(nèi)置組件中查看是否存在中間件組件。完整列表位于 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-7.0#built-in-middleware。此圖表提供了每個(gè)中間件組件的描述以及將其放置在中間件管道中的位置。除了內(nèi)置組件之外,還可以使用 NuGet 查找創(chuàng)新的中間件組件。
在本節(jié)中,我們介紹了中間件管道,理解了如何使用請(qǐng)求委托以及每個(gè)請(qǐng)求委托可以做什么,并理解了 ASP.NET Web 應(yīng)用程序可用的所有內(nèi)置中間件組件。在下一節(jié)中,我們將研究使用中間件的常見(jiàn)做法。
中間件的常見(jiàn)做法
在本節(jié)中,我們將回顧編寫(xiě)自己的中間件時(shí)的一些常見(jiàn)做法,以使 Web 應(yīng)用程序中的所有內(nèi)容都能以最佳方式運(yùn)行。讓我們開(kāi)始吧!
推遲到異步
在使用中間件時(shí),我們希望獲得盡可能好的性能,以便用戶可以開(kāi)始在應(yīng)用程序中工作。隨著越來(lái)越多的用戶繼續(xù)使用該應(yīng)用程序,性能可能會(huì)受到影響。
同步操作是執(zhí)行代碼并且應(yīng)用程序必須等待它完成的地方,這意味著它是單線程的并在應(yīng)用程序的主線程上運(yùn)行,但是當(dāng)執(zhí)行異步操作時(shí),它會(huì)創(chuàng)建一個(gè)新線程并讓框架知道在完成處理后要調(diào)用什么。這通過(guò) async/await 關(guān)鍵字表示。
對(duì)于大多數(shù)中間件操作,最好在適用時(shí)使用異步調(diào)用。這將提高中間件(和應(yīng)用程序)的性能以及更好的可擴(kuò)展性和響應(yīng)能力。
確定順序的優(yōu)先級(jí)
設(shè)置中間件的一個(gè)更重要的要點(diǎn)是確認(rèn)一切都按正確的順序進(jìn)行。
將應(yīng)用程序的要求與上一個(gè)圖表進(jìn)行比較,以確定您需要哪些中間件組件以及它們?cè)谀?Web 應(yīng)用程序中的正確順序。
例如,如果您想包含 W3C 日志記錄中間件組件(包含在 Microsoft 的內(nèi)置中間件組件中),它必須位于管道的開(kāi)頭,以記錄整個(gè)應(yīng)用程序中發(fā)出的任何后續(xù)請(qǐng)求。每個(gè)組件在管道中都有自己的位置。
整合現(xiàn)有中間件
當(dāng)您創(chuàng)建新的 ASP.NET 項(xiàng)目時(shí),您會(huì)注意到 Program.cs 中列出的 app.UseXxx() 集合。雖然這是準(zhǔn)備管道的“開(kāi)箱即用”方法,但還有其他方法可以組織和注冊(cè)應(yīng)用程序的組件。
一種方法是根據(jù)您如何將用途邏輯劃分為類似的組,同時(shí)保持組件的順序不變,來(lái)使用擴(kuò)展方法。
一個(gè)例子是將所有客戶端中間件移至其自己的擴(kuò)展方法 .UseClientOptions():
public static class WebApplicationExtensions
{
public static void UseClientOptions(this WebApplication app)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
}
}
現(xiàn)在,您的 Program.cs 文件中的代碼包含一行,并且您確切地知道擴(kuò)展方法的作用:
app.UseClientOptions();
使用這種方法時(shí),您的 Program.cs 文件會(huì)更干凈、維護(hù)得更好,并且包含的代碼行更少。
其他可能需要分區(qū)的區(qū)域如下:
UseDataXxxxx() – 應(yīng)用程序連接字符串的集中位置UseMapping()/UseRouting() – 為您的應(yīng)用程序和 API 創(chuàng)建路由集合RegisterDependencyInjection() – 將類集中在多個(gè)擴(kuò)展方法中,類似于此分組方法,但按應(yīng)用程序中的部分進(jìn)行分區(qū) - 例如,RegisterDIPayroll() 用于注冊(cè)與應(yīng)用程序的 Payroll 部分相關(guān)的類
雖然這些只是建議,但其概念是縮減 Program.cs 文件的大小,以便其他開(kāi)發(fā)人員用更少的代碼行理解該方法,并為其他開(kāi)發(fā)人員提供足夠的清晰度以進(jìn)一步擴(kuò)展該技術(shù)。
作為建議,請(qǐng)預(yù)先包含所有重要的中間件組件,并確認(rèn)應(yīng)用程序按預(yù)期運(yùn)行,然后通過(guò)創(chuàng)建要合并的組來(lái)執(zhí)行重構(gòu)。請(qǐng)記住,中間件組件的順序很重要。
封裝中間件
創(chuàng)建第一個(gè)中間件組件時(shí),您可能想按以下方式創(chuàng)建和使用它:
app.Use(async (context, next) =>
{
app.Logger.LogInformation("In our custom Middleware...");
// Prepare work for when we write to the Response
await next();
// work that happens when we DO write to the response.
});
這種方法的一個(gè)問(wèn)題是,如果您有大量自定義中間件組件,上述代碼可能會(huì)使您的 Program.cs 文件看起來(lái)有點(diǎn)混亂。
一旦您的自定義組件開(kāi)始工作,最好將其封裝到自己的類中以提高可重用性。如果我們使用前面的示例,我們的新類將如下所示:
public class MyFirstMiddleware
{
private readonly ILogger _logger;
private readonly RequestDelegate _next;
public MyFirstMiddleware(ILogger logger, RequestDelegate next)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
_logger.LogInformation("In our custom Middleware...");
// Prepare work for when we write to the Response
await _next(context);
// work that happens when we DO write to the response.
}
}
在此示例中,MyFirstMiddleware 組件是一個(gè)簡(jiǎn)單的類,它只能包含一個(gè)Invoke 或InvokeAsync 方法。如前所述,我們將使用InvokeAsync 異步方法。
如果您想知道ILogger 是如何傳入的,ASP.NET Core 在其開(kāi)箱即用的依賴項(xiàng)注入庫(kù)中自動(dòng)注冊(cè)了許多類。ILogger 就是其中一個(gè)類,因此我們不必?fù)?dān)心將其傳遞給我們的MyFirstMiddleware 組件。
我們可以像這樣在Program.cs 文件中使用我們的類:
app.UseMiddleware
但是,由于我們是優(yōu)秀的 ASP.NET 開(kāi)發(fā)人員,因此我們絕對(duì)可以改進(jìn)代碼。大多數(shù)中間件組件都附加了擴(kuò)展方法,以使其更易于使用(我們現(xiàn)在將使用以下代碼添加):
public static class MyFirstMiddlewareExtensions
{
public static IApplicationBuilder UseMyFirstMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware
}
}
我們的 Program.cs 文件現(xiàn)在更加簡(jiǎn)單和干凈了:
app.UseMyFirstMiddleware();
這些簡(jiǎn)單的做法使開(kāi)發(fā)人員的工作更易于重用和封裝。
在本節(jié)中,我們介紹了一些編寫(xiě)可維護(hù)且高效的中間件的標(biāo)準(zhǔn)方法,包括使用異步調(diào)用、優(yōu)先考慮組件的順序以及將現(xiàn)有中間件整合到擴(kuò)展方法中。我們還研究了如何通過(guò)創(chuàng)建類和擴(kuò)展方法來(lái)封裝組件,從而使代碼更易于閱讀。
創(chuàng)建表情符號(hào)中間件組件
隨著表情符號(hào)的興起……對(duì)不起,表情符號(hào)……在 2000 年代,許多舊式網(wǎng)站使用舊式的基于文本的表情符號(hào),而不是更現(xiàn)代的表情符號(hào)。舊式內(nèi)容管理系統(tǒng)(CMS)的內(nèi)容中必須包含大量這些基于文本的字符。更新網(wǎng)站內(nèi)容以用適當(dāng)?shù)谋砬榉?hào)替換所有這些表情符號(hào)聽(tīng)起來(lái)非常耗時(shí)。
在本節(jié)中,我們將應(yīng)用我們的標(biāo)準(zhǔn)來(lái)創(chuàng)建一個(gè)表情符號(hào)中間件組件,如果它檢測(cè)到基于文本的表情符號(hào),它會(huì)將其轉(zhuǎn)換為更現(xiàn)代的表情符號(hào)。
封裝中間件
有了這個(gè)新的中間件組件,我們希望在 EmojiMiddleware.cs 中的自己的類中創(chuàng)建它。
這是我們組件的初稿:
public class EmojiMiddleware
{
private readonly ILogger _logger;
private readonly RequestDelegate _next;
public EmojiMiddleware(ILogger logger, RequestDelegate next)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await _next(context);
}
}
public static class EmojiMiddlewareExtensions
{
public static IApplicationBuilder UseEmojiMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware
}
}
雖然這并不是很令人興奮,但這個(gè)樣板滿足了前面提到的構(gòu)建中間件組件的所有標(biāo)準(zhǔn),包括以下內(nèi)容:
封裝的中間件組件使用異步方法(InvokeAsync())用于重用和可讀性的擴(kuò)展方法
我們現(xiàn)在可以專注于轉(zhuǎn)換過(guò)程。
檢查組件的管道
在中間件中,有兩種處理請(qǐng)求和響應(yīng)的方法:使用流或管道。雖然管道是高性能的更好選擇,但我們將重點(diǎn)關(guān)注 EmojiMiddleware 的流。我們將在后面的章節(jié)中檢查管道。
我們的中間件流通過(guò) HttpRequest.Body 和 HttpResponse.Body 位于 HttpContext 中。在我們的 Invoke 方法中,我們方便地傳入 HttpContext。
我們的首要任務(wù)是創(chuàng)建 EmojiStream。這將接受一個(gè)簡(jiǎn)單的響應(yīng)流并將其讀入內(nèi)存。一旦我們有了 HTML,我們就可以搜索和替換表情符號(hào)。我們需要一個(gè)映射來(lái)識(shí)別基于文本的字符以及在 HTML 中用什么圖像替換它們。
為了讓我們的生活更輕松一些,我們將從 Stream 基類繼承,并簡(jiǎn)單地覆蓋特定方法以滿足我們的需求。我們的 EmojiStream 類所需的唯一實(shí)現(xiàn)是我們基于文本的表情符號(hào)到表情符號(hào)的映射和 .Write() 方法,如以下代碼所示:
public class EmojiStream: Stream
{
private readonly Stream _responseStream;
private readonly Dictionary
{
{ ":-)", " :) " },
{ ":)", " :) " },
{ ";-)", " ;) " }
};
public EmojiStream(Stream responseStream)
{
ArgumentNullException.ThrowIfNull(responseStream);
_responseStream = responseStream;
}
public override bool CanRead => _responseStream.CanRead;
public override bool CanSeek => _responseStream.CanSeek;
public override bool CanWrite => _responseStream.CanWrite;
public override long Length => _responseStream.Length;
public override long Position
{
get => _responseStream.Position;
set => _responseStream.Position = value;
}
public override void Flush()
{
_responseStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _responseStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _responseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_responseStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
var html = Encoding.UTF8.GetString(buffer, offset, count);
foreach (var emoticon in _map)
{
if (!html.Contains(emoticon.Key)) continue;
html = html.Replace(emoticon.Key, emoticon.Value);
}
buffer = Encoding.UTF8.GetBytes(html);
_responseStream.WriteAsync(buffer, 0, buffer.Length);
}
}
在代碼的開(kāi)頭,我們創(chuàng)建了要在 HTML 中查找的表情符號(hào)映射。除了 WriteAsync() 方法之外,EmojiStream 類相當(dāng)常見(jiàn)。我們將使用 GetString() 方法獲取 HTML,并在響應(yīng)中搜索每個(gè)表情符號(hào)。如果找到一個(gè),我們將用圖像標(biāo)簽替換它,最后將字節(jié)寫(xiě)回流中。
由于我們專注于在中間件中使用流,因此我們將把流傳遞給構(gòu)造函數(shù),而不是創(chuàng)建新實(shí)例。
剩下中間件部分后,我們可以在類中使用 EmojiStream:
public class EmojiMiddleware
{
private readonly RequestDelegate _next;
public EmojiMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
using var buffer = new MemoryStream();
// R用我們的緩沖區(qū)替換上下文響應(yīng)
var stream = context.Response.Body;
context.Response.Body = buffer;
// 如果有任何其他中間件組件,則調(diào)用管道的其余部分
await _next(context);
// 重置并讀出內(nèi)容
buffer.Seek(0, SeekOrigin.Begin);
// 調(diào)整響應(yīng)流以包含我們的圖像。
var emojiStream = new EmojiStream(stream);
// Reset the stream again
buffer.Seek(0, SeekOrigin.Begin);
// 將我們的內(nèi)容復(fù)制到原始流并放回
await buffer.CopyToAsync(emojiStream);
context.Response.Body = emojiStream;
}
}
雖然我們的中間件組件采用了一個(gè)簡(jiǎn)單的RequestDelegate,但組件的大部分內(nèi)容都在InvokeAsync()方法中。首先,我們?yōu)轫憫?yīng)創(chuàng)建一個(gè)新的流。接下來(lái),我們用自己的流替換標(biāo)準(zhǔn)響應(yīng)。當(dāng)我們從端點(diǎn)返回時(shí),我們創(chuàng)建EmojiStream實(shí)例并將自定義流傳遞給Response.Body。
由于HttpContext將HttpRequest.Body和HttpResponse.Body作為流公開(kāi),因此將HttpContext傳遞到自定義中間件組件中更加容易。
當(dāng)然,我們不能忘記我們的擴(kuò)展方法,如下所示:
public static class EmojiMiddlewareExtensions
{
public static IApplicationBuilder UseEmojiMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware
}
}
此擴(kuò)展方法被視為一種外觀,用于隱藏我們的 EmojiStream 在幕后執(zhí)行的操作的細(xì)節(jié)。雖然我們可以在 Program.cs 文件中使用 builder.UseMiddleware() 語(yǔ)法,但擴(kuò)展方法會(huì)對(duì)其進(jìn)行一些清理,使其看起來(lái)更專業(yè)。
最后需要做的是將 EmojiMiddleware 添加到 Program.cs 文件中的管道中:
app.UseEmojiMiddleware();
創(chuàng)建全新的 ASP.NET Core 網(wǎng)站后,我們將以下 HTML 添加到索引頁(yè)的底部:
Smile, you're on candid camera. :-) :)
It even works inside ;-) a paragraph.
當(dāng)我們運(yùn)行沒(méi)有中間件組件的應(yīng)用程序時(shí),我們會(huì)得到以下輸出(圖 3.2):
圖 3.2 – 在將 EmojiMiddleware 添加到管道之前
當(dāng)我們將 Emoji Middleware 添加到管道并再次運(yùn)行應(yīng)用程序時(shí),我們會(huì)收到以下輸出(圖 3.3):
圖 3.3 – 將 EmojiMiddleware 添加到管道之后
在本節(jié)中,我們通過(guò)將邏輯封裝在類中來(lái)構(gòu)建第一個(gè)中間件組件,使用流檢查組件管道,并在 Web 應(yīng)用程序中使用中間件組件。
柚子快報(bào)邀請(qǐng)碼778899分享:3. 中間件的最佳方法
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。