在.Net Core
中,管道往往伴隨著請求一起出現。客戶端發起Http
請求,服務端去響應這個請求,之間的過程都在管道內進行。
舉一個生活中比較常見的例子:旅遊景區。
我們都知道,有些景區大門離景區很遠,我們需要經過層層關卡才能到達景區。
我的請求最終就是去到景區,去到景區的整個過程就是管道,景區就是伺服器,層層關卡就是一個個中介軟體了,比如:門票
、停車費
、擺渡費
等等。
如果其中任何一個中介軟體卡殼了,比如我沒買門票,那別人肯定是不讓我進去,這就是管道短路了。
.NET Core
請求管道包含一系列Http
請求委託(RequestDelegate
),依次呼叫。
微軟給的圖示:
.Net Core服務
在解釋管道的使用方法之前,我們先來準備一個.Net Core
服務。
建立一個.Net Core
控制檯應用程式,並實現如下程式碼,一個簡單的使用 Kestrel
託管的服務就完成了:
internal class Program
{
static void Main(string[] args)
{
new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup2>()
.Build()
.Start();
Console.ReadLine();
}
}
public class Startup
{
public void Configure(IApplicationBuilder app)
{
}
}
這也是.Net Core
的優點之一,只選擇我們需要的,摒棄那些多餘的功能。優點是優點,一般開發中也犯不上這樣去做。
Kestrel
託管預設監聽埠:5000
管道中介軟體
微軟這邊內建了三個擴充套件函式供我們構建自己的中介軟體:
- Use
- Map
- Run
其中Use
和Map
函式還提供了對應的分支擴充套件:UseWhen
、MapWhen
、UseMiddleware
。下面我們一個個來解釋。
app.Use
Use
是最常用的一種模式,承接上一個請求並執行下一個請求的任務
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
Console.WriteLine("middleware1");
await next.Invoke();
});
app.Use(async (context, next) =>
{
Console.WriteLine("middleware2");
});
}
app.UseWhen
UseWhen
在Use
的基礎上提供了條件分支的功能
app.UseWhen(context =>
// 判斷請求路徑的開頭是否是/h
context.Request.Path.StartsWithSegments(new PathString("/h")),
c => c.Use(async (context, next) =>
{
Console.WriteLine("middleware1");
await next.Invoke();
})
);
app.Use(async (context, next) =>
{
Console.WriteLine("middleware2");
});
app.Map
Map
我們可以理解成專為請求路徑擴充套件的分支中介軟體,可以根據請求路徑去處理對應分支邏輯,與上面的UseWhen
例子效果類似,但更加方便。
app.Map("/h", _app =>
{
_app.Use(async (context, next) =>
{
Console.WriteLine("hello world");
});
});
app.MapWhen
MapWhen
與UseWhen
類似,都是在請求上下文的基礎上去擴充套件分支,比Map
更加靈活。
app.MapWhen(context => { return context.Request.Query["name"] == "tony"; }, _app => {
_app.Use(async (context, next) => {
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("i 服了 you");
});
});
app.Run
Run
一般用於斷路或請求管道的末尾,不會將請求傳遞下去
app.Run(async context =>
{
await context.Response.WriteAsync("hello world");
});
UseMiddleware
將一個完整的類新增到管道中介軟體,也就是將上面的請求委託,用類以及函式的形式替代了,便於我們的程式碼管理。
app.UseMiddleware<DotnetboyMiddleware>();
public class DotnetboyMiddleware
{
private readonly RequestDelegate _next;
private readonly string _name;
public DotnetboyMiddleware(RequestDelegate next, string name)
{
_next = next;
_name = name;
}
public Task Invoke(HttpContext context)
{
context.Response.WriteAsync($"my name is {_name}").Wait();
return this._next(context);
}
}
微軟內建的一些管道中介軟體擴充套件函式就介紹完了,下面我們實現一下微軟例項圖示中的效果:
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
Console.WriteLine("middleware1 : in");
await next.Invoke();
Console.WriteLine("middleware1 : out");
});
app.Use(async (context, next) =>
{
Console.WriteLine("middleware2 : in");
await next.Invoke();
Console.WriteLine("middleware2 : out");
});
app.Run(async context =>
{
Console.WriteLine("Hello World");
await context.Response.WriteAsync("Hello World");
});
}
從上面的例子中我們可以看到,中介軟體都是由上而下依次執行,由每個中介軟體決定是否繼續執行下一個中介軟體,最終到響應結果。
如果哪個中介軟體決定不往下執行,那通道也就短路了,比如我們去掉 middleware2
的 await next.Invoke();
執行到 Console.WriteLine("middleware2 : out");
就短路了,此路不通,原路返回。
因為管道中介軟體執行邏輯的關係,我們在實際開發中要注意兩點:
-
1、謹慎使用管道短路
-
2、注意中介軟體的使用順序,比如:路由中介軟體肯定是要在認證中介軟體前面執行,有中介軟體需要訪問檔案,在此之前就必須先執行開放靜態檔案的中介軟體