一、前言
到這篇文章為止,關(guān)于.NET "溫故知新"系列的基礎(chǔ)知識(shí)就完結(jié)了,從這一系列的系統(tǒng)回顧和再學(xué)習(xí),對(duì)于.NET core、ASP.NET CORE又有了一個(gè)新的認(rèn)識(shí)。
不光是從使用,還包括這些知識(shí)點(diǎn)的原理,雖然深入原理談不上,但對(duì)于日常使用也夠了,我想的是知其然,知其所以然。
在實(shí)際開發(fā)過(guò)程中可能是知道怎么使用就行,但系統(tǒng)學(xué)習(xí)了這些基本的框架、組件、或者說(shuō)原理后,對(duì)于我們軟件設(shè)計(jì)、開發(fā)、擴(kuò)展和解決問(wèn)題還是有幫助的。
剛好到2023新年前趕著寫完,也算對(duì)自己這個(gè)系列的一個(gè)交代,實(shí)際上我平時(shí)基本不使用ASP.NET CORE,目前我主要開發(fā)桌面程序,還是用的winform。
寫這個(gè)系列的初衷是想緊跟.NET的發(fā)展進(jìn)程,同時(shí)儲(chǔ)備基礎(chǔ)知識(shí),平時(shí)還搞一些微服務(wù)(Java)、NLP、OCR、知識(shí)圖譜、前端(Vue3),只要需要反正啥都搞,沒(méi)必要固執(zhí),技術(shù)只是手段,不是目的。
那么接下來(lái)就繼續(xù)簡(jiǎn)單的梳理一下中間件,歡迎對(duì)這個(gè)系列拍磚!
二、中間件
中間件是一種裝配到應(yīng)用管道以處理請(qǐng)求和響應(yīng)的軟件。 每個(gè)組件:
- 選擇是否將請(qǐng)求傳遞到管道中的下一個(gè)組件。
- 可在管道中的下一個(gè)組件前后執(zhí)行工作。
這個(gè)是關(guān)于中間件概念的概括,官方的概括是相當(dāng)精準(zhǔn),那么我們就圍繞管道、傳遞、組件來(lái)看看中間件。
請(qǐng)求委托用于生成請(qǐng)求管道。 請(qǐng)求委托處理每個(gè) HTTP 請(qǐng)求。使用 Run、Map 和 Use 擴(kuò)展方法來(lái)配置請(qǐng)求委托。
我們照例新建一個(gè)ASP.NET CORE Web API 項(xiàng)目:WebAPI_Middleware
namespace WebAPI_Middleware
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
在Program.cs 中我們看到前面部分builder
是配置依賴注入的東西,這部分可以參看.net 溫故知新【13】:Asp.Net Core WebAPI 使用依賴注入DI 。
app
使用Use
擴(kuò)展用于中間件添加到管道中
Map
基于給定請(qǐng)求路徑的匹配項(xiàng)來(lái)創(chuàng)建請(qǐng)求管道分支
Run
委托始終為終端,用于終止管道。
中間件的執(zhí)行順序過(guò)程如下:
三、Map
我們將上面自動(dòng)創(chuàng)建的東西全都刪除,用Map
來(lái)匹配路由,然后通過(guò)不同的代理處理請(qǐng)求。
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
//匹配map1 請(qǐng)求
app.Map("/map1", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
}));
//匹配map2 請(qǐng)求
app.Map("/map2", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map2 run");
});
}));
app.Run();
}
}
- 請(qǐng)求map1 我們輸出:map1 run
- 請(qǐng)求map2 我們輸出:map2 run
Asp.Net Core MapControllers
的擴(kuò)展方法也是類似道理,用來(lái)匹配路由調(diào)用處理程序。
四、Run
在上面的 Map 后面我們使用的處理方法中 Run 用于終止管道。也就是說(shuō)在該管道中如果調(diào)用了 Run 那么就直接返回了,即使你后面還添加了 Use 也不會(huì)執(zhí)行。
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
Map 相當(dāng)于是迎客進(jìn)門,Map 上了就用指定的管道進(jìn)行處理,如果沒(méi)有 Map 上就調(diào)用主管道,也就是主管道上的其他中間件也會(huì)執(zhí)行處理。比如我們?cè)偌右粋€(gè) Run 用于沒(méi)匹配上路由也輸出點(diǎn)信息。
加了context.Response.ContentType = "text/plain; charset=utf-8";
不然中文會(huì)亂碼。
因?yàn)?Run 是終結(jié)點(diǎn),那這個(gè)管道中我還想加其他處理怎么辦呢,這個(gè)時(shí)候就該輪到 Use 出場(chǎng)了。
五、Use
用 Use 將多個(gè)請(qǐng)求委托鏈接在一起。 next 參數(shù)表示管道中的下一個(gè)委托。 可通過(guò)不調(diào)用 next 參數(shù)使管道短路。
首先我們?cè)谕饷嫣砑觾蓚€(gè) Use,不放到 Map 中,這樣的話就只有未匹配到的路由會(huì)調(diào)用
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
}));
app.Map("/map2", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map2 run");
});
}));
//Use1
app.Use(async (context, next) =>
{
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("第 1 個(gè)Use 開始!\r\n", Encoding.UTF8);
await next();
await context.Response.WriteAsync("第 1 個(gè)Use 結(jié)束!\r\n", Encoding.UTF8);
});
//Use2
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("第 2 個(gè)Use 開始!\r\n", Encoding.UTF8);
await next();
await context.Response.WriteAsync("第 2 個(gè)Use 結(jié)束!\r\n", Encoding.UTF8);
});
//結(jié)束管道處理
app.Run(async context =>
{
await context.Response.WriteAsync("未匹配處理!\r\n", Encoding.UTF8);
});
app.Run();
}
}
最后執(zhí)行的路徑和最開始的圖是一致的。
為什么將context.Response.ContentType = "text/plain; charset=utf-8";
放到第一個(gè) Use 呢,因?yàn)槿绻诺?Run 里面會(huì)報(bào)錯(cuò),改變了 Header 標(biāo)頭。所以理論上也不要在 Use 里面發(fā)送響應(yīng)WriteAsync,此處為了演示所以這么寫。
六、中間件類
上面的代理方法可以移動(dòng)到類中,這個(gè)類就是中間件類。中間件類需要如下要求:
- 具有類型為 RequestDelegate 的參數(shù)的公共構(gòu)造函數(shù)。
- 名為 Invoke 或 InvokeAsync 的公共方法。 此方法必須:
返回 Task。
接受類型 HttpContext 的第一個(gè)參數(shù)。
構(gòu)造函數(shù)和 Invoke/InvokeAsync 的其他參數(shù)由依賴關(guān)系注入 (DI) 填充。
將上面的未匹配路由處理邏輯移動(dòng)到中間件類中:
- TestMiddleware1:
public class TestMiddleware1
{
private readonly RequestDelegate _next;
public TestMiddleware1(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("第 1 個(gè)Use 開始!\r\n", Encoding.UTF8);
await _next(context);
await context.Response.WriteAsync("第 1 個(gè)Use 結(jié)束!\r\n", Encoding.UTF8);
}
}
- TestMiddleware2
public class TestMiddleware2
{
private readonly RequestDelegate _next;
public TestMiddleware2(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync("第 2 個(gè)Use 開始!\r\n", Encoding.UTF8);
await _next(context);
await context.Response.WriteAsync("第 2 個(gè)Use 結(jié)束!\r\n", Encoding.UTF8);
}
}
-
Program
-
運(yùn)行
此處的中間件使用有順序問(wèn)題,如果我先app.UseMiddleware<TestMiddleware2>()
因?yàn)?TestMiddleware1 修改了標(biāo)頭,根據(jù)約定是不允許的,所以程序是有報(bào)錯(cuò)。
因此中間件組件的順序定義了針對(duì)請(qǐng)求調(diào)用這些組件的順序,以及響應(yīng)的相反順序。 此順序?qū)τ诎踩?、性能和功能至關(guān)重要。
七、中間件順序
以上是內(nèi)置中間件的默認(rèn)順序規(guī)則,具體如何使用內(nèi)置中間件,可參閱官方資料。
八、寫在最后
以上就是關(guān)于中間件的部分知識(shí),結(jié)合我自己的理解做了前后銜接的梳理邏輯。
官方網(wǎng)站更多的是講解每個(gè)知識(shí)點(diǎn)的細(xì)節(jié),前后需要結(jié)合起來(lái)理解,當(dāng)然我還是強(qiáng)烈建議跟著官方文檔學(xué)習(xí),而且是最權(quán)威最可信的:ASP.NET Core 中間件文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-800600.html
這個(gè)系列歷時(shí)2年,工作生活都比較忙,也有放縱啥事不相干的時(shí)候,中間斷斷續(xù)續(xù)的,總算是堅(jiān)持完了。很多東西就是這樣,累了就休息一下貴在堅(jiān)持,即使再慢,積累的成果也有收獲。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-800600.html
到了這里,關(guān)于.net 溫故知新【17】:Asp.Net Core WebAPI 中間件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!