iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
3

在ASP.Net Core中Middleware的設計非常直覺跟彈性,
本篇將記錄ASP.Net Core Middleware的相關用法。

同步發表於個人點部落 - [鐵人賽Day04] ASP.Net Core MVC 進化之路 - 淺談Middleware

情境

在介紹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預設在StartupConfigure設定,
ASP.Net Core預設內建了許多好用的Middleware
如驗證(Authentication)、回應壓縮(Response Compression)、URL重寫(URL Rewriting)等,
如需要更詳細的資訊可以參考MSDN

我們可以使用RunUseMap自訂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


上一篇
[鐵人賽Day03] - 建立ASP.Net Core MVC專案
下一篇
[鐵人賽Day05] - 靜態檔案(Static Files)
系列文
菜鳥練等區-ASP.Net Core MVC進化之路30

尚未有邦友留言

立即登入留言