在ASP.Net Core中**Middleware**的設計非常直覺跟彈性,
本篇將記錄ASP.Net Core Middleware的相關用法。
在介紹Middleware前,先看個情境題:
中午去看電影,
下午又去健身房,
走到鋼鐵三路要搭公車回家時發現悠遊卡掉了,
請問你會去哪裡找?
(假設悠遊卡就掉在這三個地方裡)
如果以筆者記性這麼差的人,
我會按照電影院 -> 健身房 -> 咖啡廳的路線順序去找。
不過假設我在健身房找到悠遊卡,那我就不會再去咖啡廳,
而由於這條路是死巷,所以我只好沿原路返回鋼鐵三路。
這就是Middleware路由的運作方式
Middleware中文翻譯成「中介軟體」,
是指從發出請求(Request)之後,
到接收回應(Response)這段來回的途徑上,
用來處理特定用途的程式。
而MSDN上用管線(Pipeline)來形容往返的過程。
比較常見的Middleware有身份驗證(Identity)、路由(Routing)或回應壓縮(Response Compression)等。
從上圖可以很清楚的看到,
Request到最裡面(Middleware 5)後,
要再沿著原路回去(後進先出,LIFO)。
一個Middleware可以分成三大部分:
- before logic:指定Request Pipeline經過時執行的邏輯。
- next:呼叫下一個Middleware(也可以決定不呼叫)。
- after logic:指定Request Pipeline經過時執行的邏輯。
Middleware預設在Startup中Configure設定,
.Net Core預設內建了許多好用的Middleware,
如驗證(Authentication)、回應壓縮(Response Compression)、URL重寫(URL Rewriting)等,
如需要更詳細的資訊可以參考MSDN。
我們可以使用Run、Use、Map自訂Middleware,
簡單說明一下其中的差別。
- Run:是所有Middleware中的最末端的行為,可以想成它是一道牆,碰到它之後Pipeline則開始回流。
- Use:一般會使用Use進行自訂的Middleware擴充,能透過呼叫next()指定執行下一層Middleware(可加入條件判斷決定是否呼叫),也可指定在管線回流時所要執行的行為。
- Map:主要在判斷路由規則是否符合預期,符合則執行區間內容。
以下為範例程式碼Startup:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("middleware - use test before map check - request in\n");
var condition = true;
if (condition)
{
await next();
}
await context.Response.WriteAsync("middleware - use test before map check - response out\n");
});
app.Map("/map1", applicationBuilder =>
{
applicationBuilder.Use(async (context, next) =>
{
await context.Response.WriteAsync("middleware - use test in map1 - request in\n");
await next.Invoke();
await context.Response.WriteAsync("middleware - use test in map1 - response out\n");
});
applicationBuilder.Run(async context =>
{
await context.Response.WriteAsync("middleware - run test in map1\n");
});
});
app.Map("/map2", applicationBuilder =>
{
applicationBuilder.Run(async context =>
{
await context.Response.WriteAsync("middleware - run test only in map2\n");
});
});
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("middleware - use test after map check - request in\n");
var condition = true;
if (condition)
{
await next();
}
await context.Response.WriteAsync("middleware - use test after map check - response out\n");
});
app.Run(async context =>
{
await context.Response.WriteAsync("middleware - run test in the end\n");
});
}
接著在瀏覽器網址列測試。
輸入https://localhost:{your_port}/
輸入https://localhost:{your_port}/map1
輸入https://localhost:{your_port}/map2
補充一下,
如果使用Use指定了next()但後面卻沒有其他Middleware行為,
這樣編譯上是檢查不出來的,但執行後則會失敗。
如果有判斷是否有下一層Middleware的方式,
再麻煩各路大神提點,
Middleware的筆記就先寫到這邊。
參考
https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1