欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ASP.NET?Core自定義中間件的方式詳解

 更新時(shí)間:2022年08月20日 10:01:18   作者:姜承軒  
這篇文章主要介紹了ASP.NET?Core自定義中間件的方式,雖然ASP.NET?Core為我們提供了一組豐富的內(nèi)置中間件,但有些時(shí)候我們可能會(huì)需要自定義一些中間件,將其穿插到管道中,以便滿足我們特定業(yè)務(wù)場(chǎng)景的需求,所以本文將介紹3種方式來滿足自定義中間件的需求

ASP.NET Core應(yīng)用本質(zhì)上,其實(shí)就是由若干個(gè)中間件構(gòu)建成的請(qǐng)求處理管道。管道相當(dāng)于一個(gè)故事的框架,而中間件就相當(dāng)于故事中的某些情節(jié)。同一個(gè)故事框架采用不同的情節(jié)拼湊,最終會(huì)體現(xiàn)出不同風(fēng)格的故事。而我們的ASP.NET Core應(yīng)用也正是如此,同一管道采用不同的中間件組合,最終也會(huì)呈現(xiàn)出不同的應(yīng)用形態(tài)。

從上述的概念種可以看出,中間件在ASP.NET Core應(yīng)用有著舉足輕重的地位。雖然ASP.NET Core為我們提供了一組豐富的內(nèi)置中間件,但有些時(shí)候我們可能會(huì)需要自定義一些中間件,將其穿插到管道中,以便滿足我們特定業(yè)務(wù)場(chǎng)景的需求,所以本文將介紹3種方式來滿足自定義中間件的需求。

1.委托形式

在應(yīng)用程序代碼中,我們可以從用于注冊(cè)中間件的Use方法中看出,所謂管道中的中間件其實(shí)就是一種委托類型的對(duì)象,這個(gè)具體的委托對(duì)象體現(xiàn)為“Fun<RequestDelegate,RequestDelegate>”。

從Fun<RequestDelegate,RequestDelegate>委托的定義可以看出,該委托類型的入?yún)⒑头祷刂刀际且粋€(gè)RequestDelegate委托類型的對(duì)象。RequestDelegate委托類型其實(shí)就是管道在代碼中的體現(xiàn)形式,該委托類型承載很多關(guān)于請(qǐng)求響應(yīng)的重要信息,定義如下:

public delegate Task RequestDelegate(HttpContext context);

Fun<RequestDelegate,RequestDelegate>委托中,入?yún)⒌腞equestDelegate對(duì)象表示由上一個(gè)中間件構(gòu)建的管道,返回值的RequestDelegate對(duì)象表示:將當(dāng)前中間件基于上一個(gè)管道處理后生成的新管道。由于中間件體現(xiàn)為一個(gè)Fun<RequestDelegate,RequestDelegate>委托對(duì)象,那么這就代表我們可以定義一個(gè)與該委托具有一致聲明的方法作為自定義中間件的方式。具體的代碼實(shí)現(xiàn)方式如下:

//創(chuàng)建應(yīng)用
var app = WebApplication.Create(args);

//轉(zhuǎn)換獲得應(yīng)用建造者
IApplicationBuilder appBuilder = app;

//注冊(cè)自定義的中間件
appBuilder.Use(SayHi);

//運(yùn)行應(yīng)用
app.Run();

//定義為Fun<RequestDelegate,RequestDelegate>類型的方法
static RequestDelegate SayHi(RequestDelegate  request)
    => httpContext => httpContext.Response.WriteAsync("Hello");

上面的代碼是在一個(gè)原始的控制臺(tái)程序中編寫的,并且自行進(jìn)行了主機(jī)應(yīng)用的構(gòu)建。在代碼中定義了一個(gè)和Fun<RequestDelegate,RequestDelegate>委托簽名一致的SayHi方法,并以此方法作為中間件進(jìn)行了引用。雖然這是一個(gè)可行的方式,但在實(shí)際開發(fā)的工作場(chǎng)景中,其實(shí)很少會(huì)使用委托形式作為自定義中間件的方式。在此處之所以演示這種形式,主要是為了表面中間件本質(zhì)是一個(gè)委托,并且不管通過什么形式去定義中間件,它最終都會(huì)體現(xiàn)為一個(gè)Fun<RequestDelegate,RequestDelegate>委托對(duì)象。

2.強(qiáng)類型中間件

在實(shí)際的開發(fā)過程中,基本上都會(huì)將自定義的中間件定義為一個(gè)具體類型,而對(duì)于使用強(qiáng)類型的中間件而言,則我們定義的中間件類型必須實(shí)現(xiàn)IMiddleware接口。既然通過一個(gè)具體類型來定義中間件,類型在使用上則勢(shì)必會(huì)與其他類型產(chǎn)生依賴關(guān)聯(lián)性,那么對(duì)于中間件類型中依賴服務(wù)的實(shí)例化,框架則要求我們使用依賴注入的方式。接下來我們將通過代碼示例演示如何定義一個(gè)強(qiáng)類型的中間件。

2.1.定義中間件的依賴

下面代碼定義的類型是我們預(yù)先為中間件類型定義的依賴項(xiàng),ISeasonTips接口類型的作用主要是,根據(jù)不同月份獲取對(duì)應(yīng)的季節(jié),并輸出對(duì)應(yīng)季節(jié)的注意事項(xiàng),其中SeasonTips類型是接口的默認(rèn)實(shí)現(xiàn)。

public interface ISeasonTips
    {
        string Prompt(DateTimeOffset time);
    }

    public class SeasonTips : ISeasonTips
    {
        //根據(jù)不同月份提示季節(jié)注意事項(xiàng)
        public string Prompt(DateTimeOffset time) => time.Month switch
        {
            var h when h >= 3 && h <= 5 => "春天到了,早晚溫差比較大,要注意別感冒。",
            var h when h >= 6 && h <= 8 => "夏天到了,天氣炎熱,要注意別防嗮。",
            var h when h >= 9 && h <= 11 => "秋天到了,天氣干燥,要注意多喝水。",
            _ => "冬天到了,天氣寒冷,要注意防寒保暖。"

        }; //END Prompt()  

    }

2.2.定義中間件類型

下面的代碼中,我們定義了一個(gè)名為SeasonMiddleware的中間件類型,并實(shí)現(xiàn)IMiddleware接口。該中間件的處理請(qǐng)求的邏輯在InvokeAsync方法中,該方法調(diào)用其依賴類型的Prompt方法,根據(jù)當(dāng)前時(shí)間獲取當(dāng)前季節(jié)的注意事項(xiàng)進(jìn)行輸出。在該調(diào)用該方法后,我們還對(duì)InvokeAsync的另一個(gè)參數(shù):“RequestDelegate類型的委托對(duì)象”進(jìn)行了調(diào)用,以便執(zhí)行管道中的下一個(gè)中間件。另外,對(duì)于中間件依賴的類型ISeasonTips,我們將其定義在構(gòu)造函數(shù)的參數(shù)列表上,以便依賴注入容器提供相應(yīng)的實(shí)例。

/// <summary>
    /// 強(qiáng)類型中間件
    /// </summary>
    public class SeasonMiddleware : IMiddleware
    {
        //依賴類型,通過構(gòu)造函數(shù)進(jìn)行依賴注入
        private readonly ISeasonTips _seasonTips;
        public SeasonMiddleware(ISeasonTips seasonTips)
        {
            _seasonTips = seasonTips;
        }

        //調(diào)用依賴的“季節(jié)提示類型”,根據(jù)當(dāng)前時(shí)間獲取當(dāng)前季節(jié)的注意事項(xiàng),并進(jìn)行響應(yīng)輸出
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            await context.Response.WriteAsync(_seasonTips.Prompt(DateTimeOffset.Now));

            //調(diào)用管道中的下一個(gè)中間件
            await next(context);
        }  // END InvokeAsync()

    }  // END Class

在下面的代碼中我們對(duì)自定義的“強(qiáng)類型中間件”進(jìn)行了應(yīng)用。由于“強(qiáng)類型中間件”的實(shí)例以及依賴都是由依賴注入容器提供的,所以不僅要對(duì)依賴的服務(wù)進(jìn)行注冊(cè),還要對(duì)自身的中間件類型進(jìn)行服務(wù)注冊(cè)。在服務(wù)注冊(cè)之后,我們使用WebApplication對(duì)象的UseMiddleware<SeasonMiddleware>擴(kuò)展方法,將該中間件添加到應(yīng)用程序的請(qǐng)求管道中。由于在該中間件后沒有其他中間件的處理,所以我們通過調(diào)用Run擴(kuò)展方法注冊(cè)了管道末端的中間件,以便結(jié)束當(dāng)前請(qǐng)求,將響應(yīng)輸出到客戶端。

using dotNet6Demo;

//創(chuàng)建“應(yīng)用建造者”
var builder = WebApplication.CreateBuilder(args);

//服務(wù)注冊(cè)
builder.Services.AddSingleton<ISeasonTips, SeasonTips>().AddSingleton<SeasonMiddleware>();

//構(gòu)建應(yīng)用
var app = builder.Build();

//引用強(qiáng)類型中間件
app.UseMiddleware<SeasonMiddleware>();

//末端的中間件
app.Run(async (context) =>
{
    await context.Response.WriteAsync("請(qǐng)求結(jié)束");
});

//運(yùn)行應(yīng)用
app.Run();

到目前為止,結(jié)合本示例以上的3個(gè)步驟,啟動(dòng)運(yùn)行程序就可以驗(yàn)證自定義強(qiáng)類型中間件的效果了。

3.基于約定的中間件

對(duì)于ASP.NET的開發(fā)者而言,基于約定的編程模式應(yīng)該不會(huì)陌生。例如在ASP.NET MVC框架中,“Action”默認(rèn)查找視圖就有一種基于約定的規(guī)則,即“Action”首先會(huì)在Views目錄中查找與當(dāng)前“Controller”同名的目錄,然后在該目錄中查找與“Action”同名的視圖文件。這種基于約定的設(shè)計(jì)方式,在自定義中間件領(lǐng)域也同樣使用到了,即基于約定的中間件。

3.1.約定規(guī)則

基于約定的中間件它不必像強(qiáng)類型中間件那樣,必須實(shí)現(xiàn)IMiddleware接口或繼承某些基類,它只用按照框架約定的方式定義中間件類型即可,具體的約定規(guī)則如下:

  1. 中間件類型必須要定義為一個(gè)公共的、可供外界實(shí)例化的類型,靜態(tài)類型無效;
  2. 構(gòu)造函數(shù)的參數(shù)中必須包含RequestDelegate類型,如果存在依賴類型則也必須包含在構(gòu)造函數(shù)中;

必須定義InvokeAsync或Invoke方法,方法簽名為:public Task Invoke(HttpContext context);

對(duì)以上的約定進(jìn)行一個(gè)補(bǔ)充說明:構(gòu)造函數(shù)的參數(shù)列表要包含依賴的類型,是為了依賴注入容器對(duì)依賴類型提供實(shí)例;RequestDelegate參數(shù)具有傳遞性,表示由后續(xù)中間件構(gòu)建的管道,當(dāng)前中間件利用它將請(qǐng)求轉(zhuǎn)交給后續(xù)管道進(jìn)行處理。InvokeAsync或Invoke方法主要是代表中間件在管道中處理請(qǐng)求的邏輯。

3.2.應(yīng)用實(shí)現(xiàn)

下面我們?cè)?ldquo;強(qiáng)類型中間件”示例的基礎(chǔ)上,根據(jù)約定規(guī)則將SeasonMiddleware類型改造為“基于約定的中間件”,代碼如下:

/// <summary>
    /// 基于約定的中間件
    /// </summary>
    public class SeasonMiddleware
    {
        private readonly ISeasonTips _seasonTips;
        private readonly RequestDelegate _next;

        public SeasonMiddleware(ISeasonTips seasonTips, RequestDelegate next)
        {
            _seasonTips = seasonTips;
            _next = next;
        }

        //調(diào)用依賴的“季節(jié)提示類型”,根據(jù)當(dāng)前時(shí)間獲取當(dāng)前季節(jié)的注意事項(xiàng),并進(jìn)行響應(yīng)輸出
        public async Task InvokeAsync(HttpContext context)
        {
            await context.Response.WriteAsync(_seasonTips.Prompt(DateTimeOffset.Now));
            //調(diào)用管道中的下一個(gè)中間件
            await _next(context);

        }  // END InvokeAsync()

    }  // END Class

在中間件引用方面,“基于約定的中間件”同樣可以使用“app.UseMiddleware<SeasonMiddleware>()”的方式進(jìn)行引用,但是在此我們介紹一種較為常用的方式,就是將自定義中間件的引用方式進(jìn)行封裝,將其作為IApplicationBuilder類型的擴(kuò)展方法來使用,擴(kuò)展方法定義的代碼如下:

public static class SeasonMiddlewareExtensions
    {
        public static IApplicationBuilder UseSeason(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<SeasonMiddleware>();
        }
    }

接下來在示例應(yīng)用方面,將其調(diào)整為使用“基于約定中間件”的形式,并使用擴(kuò)展方法引用中間件。

using dotNet6Demo;

//創(chuàng)建“應(yīng)用建造者”
var builder = WebApplication.CreateBuilder(args);

//服務(wù)注冊(cè)
builder.Services.AddSingleton<ISeasonTips, SeasonTips>();

//構(gòu)建應(yīng)用
var app = builder.Build();

//通過自定義擴(kuò)展方法 引用中間件
app.UseSeason();

//末端的中間件
app.Run(async (context) =>
{
    await context.Response.WriteAsync("請(qǐng)求結(jié)束");
});

//運(yùn)行應(yīng)用
app.Run();

在對(duì)以上中間件應(yīng)用方面,我們能可以看出“基于約定的中間件”類型并沒有進(jìn)行服務(wù)注冊(cè),而“強(qiáng)類型中間件”類型卻進(jìn)行了服務(wù)注冊(cè),這是因?yàn)閮烧咴谔峁?shí)例的方式上有著本質(zhì)的區(qū)別。

“基于約定的中間件”的實(shí)例是在應(yīng)用啟動(dòng)時(shí)便可提供的,并且只能指定的一個(gè)固定的生命周期模式“Singleton”,所以該類型中間件具有和應(yīng)用程序一樣的生存期,直到應(yīng)用程序關(guān)閉才會(huì)釋放。

“強(qiáng)類型中間件”的實(shí)例并不是在應(yīng)用啟動(dòng)時(shí)提供的,它需要根據(jù)服務(wù)注冊(cè)時(shí)指定的生命周期,來決定創(chuàng)建提供的時(shí)機(jī)。例如“強(qiáng)類型中間件”注冊(cè)的生命周期為“Scoped”,那么依賴注入容器會(huì)根據(jù)客戶端的請(qǐng)求實(shí)時(shí)創(chuàng)建中間件的實(shí)例,請(qǐng)求處理完成后才會(huì)被釋放。

總結(jié)

中間件的使用地位在ASP.NET Core中絕對(duì)是毋庸置疑的,那么對(duì)于較為復(fù)雜的項(xiàng)目而言,自定義中間件的需求絕對(duì)是“繞不開的彎”,所以我們必須掌握自定義中間件的方式。

本文介紹了3種可以實(shí)現(xiàn)自定義ASP.NET Core中間件的方式。其中第一種并不推崇作為實(shí)戰(zhàn)運(yùn)用的手段,其目的是為了讓我們明白:中間件最終的體現(xiàn)形式其實(shí)就是一個(gè)委托對(duì)象,該委托對(duì)象承載了請(qǐng)求上下信息,并具有傳遞性。在實(shí)際的使用中,我們可以在第二種和第三種中進(jìn)行選擇,也就是“強(qiáng)類型中間件”和“基于約定的中間件”,從兩者的特點(diǎn)上來看,“基于約定的中間件”在使用方面會(huì)更加的方便,但是其生命周期模式只能局限于Singleton。而“強(qiáng)類型中間件”可以通過服務(wù)注冊(cè)為中間件實(shí)例指定任意的生命周期模式,相比更加靈活。

對(duì)于具體的選擇,我們想我們還是交給我們實(shí)際的運(yùn)用場(chǎng)景。

如果想了解更多關(guān)于自定義 ASP.NET Core 中間件的方式,可以訪問如下的官方文檔:

寫入自定義 ASP.NET Core 中間件 | Microsoft Docs

到此這篇關(guān)于ASP.NET Core自定義中間件的方式的文章就介紹到這了,更多相關(guān)ASP.NET Core自定義中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論