學習Asp.Net Core中介軟體

起因

原文是在Asp。Net Core 3。1寫,今天查看了一下最新的原始碼,發現變化,便進行了遷移。

從Asp。Net(Webform/Mvc/Api)到Asp。Net Core不同就是請求管道換成中介軟體,在Asp。Net WebForm到MVC請求管道(底層)變化不是很大。

中介軟體是一種在應用管道以處理請求和響應的軟體

作用:

選擇是否將請求傳遞到管道中的下一個元件

可在管道中的下一個元件前後執行工作

官方文件中的關於中介軟體的執行圖:

學習Asp.Net Core中介軟體

Asp。Net Core 中介軟體處理請求和響應請求的執行過程

編寫第一個中介軟體

在Asp。Net Core Web程式中,在Startup類Configure方法增加以下程式碼:

app。Use(async (context, next) =>{ //context為HttpContext上下文包含HttpRequest(請求資訊)和HttpResponse(響應資訊) //context。Request為HttpRequest //context。Response為和HttpResponse await context。Response。WriteAsync(“hello kestrel,hello asp。net core \n”);});

該程式根目錄執行命令:

dotnet run

預設配置的情況下直接訪問:

http://localhost:5000

學習Asp.Net Core中介軟體

訪問我們編寫的中介軟體,檢視訪問的內容

學習中介軟體執行順序

編寫3箇中間件,並在控制檯輸出順序。

app。Use(next =>{ Console。WriteLine(“1”); return async c => { //_logger。LogInformation(“===============/========”); await c。Response。WriteAsync(“kestrel exec middleware start 1 \n”); await next。Invoke(c); await c。Response。WriteAsync(“kestrel exec middleware end 1 \n”); };});app。Use(next =>{ Console。WriteLine(“2”); return async c => { //_logger。LogInformation(“===============/========”); await c。Response。WriteAsync(“kestrel exec middleware start 2 \n”); await next。Invoke(c); await c。Response。WriteAsync(“kestrel exec middleware end 2 \n”); };});app。Use(next =>{ Console。WriteLine(“3”); return async c => { //_logger。LogInformation(“===============/========”); await c。Response。WriteAsync(“kestrel exec middleware start 3 \n”); await c。Response。WriteAsync(“kestrel exec middleware end 3 \n”); };});

檢視Kestrel啟動後的列印順序:

學習Asp.Net Core中介軟體

看Kestrel啟動後的列印中介軟體的順序

在瀏覽器中訪問:

http://localhost:5000

學習Asp.Net Core中介軟體

Asp。Net Core多箇中間件執行過程

控制檯的順序和瀏覽器的結果,是相反的。為什麼是相反的? 帶著好奇心我們去看看原始碼是什麼樣的。

ApplicationBuilder。cs

檔案地址在專案位置:

src/Http/Http/src/Builder

///

/// 存放HttpContext 委託集合/// private readonly IList> _components = new List>();/// /// Use函式只是把中介軟體(委託)放到集合/// /// /// public IApplicationBuilder Use(Func middleware){ _components。Add(middleware); return this;}public IApplicationBuilder New(){ return new ApplicationBuilder(this);}/// /// Build函式才是執行中介軟體的/// /// public RequestDelegate Build(){ RequestDelegate app = context => { // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened。 // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware。 var endpoint = context。GetEndpoint(); var endpointRequestDelegate = endpoint?。RequestDelegate; if (endpointRequestDelegate != null) { var message = $“The request reached the end of the pipeline without executing the endpoint: ‘{endpoint!。DisplayName}’。 ” + $“Please register the EndpointMiddleware using ‘{nameof(IApplicationBuilder)}。UseEndpoints(。。。)’ if using ” + $“routing。”; throw new InvalidOperationException(message); } context。Response。StatusCode = StatusCodes。Status404NotFound; return Task。CompletedTask; }; //_components呼叫Reverse 進行反轉 所以在啟動的時候先列印最後一箇中間件 //那為什麼在請求的時候,中介軟體的執行又按照我們新增中介軟體的順序呢? //是因為_components在迴圈結束,app指向的是第一個中介軟體 //在第一個中介軟體中輸出kestrel exec middleware start 1 呼叫 next(呼叫第二個) 形成鏈式呼叫 //所以在結尾的中介軟體中不能進行next foreach (var component in _components。Reverse()) { //原本是component(app) 後跟Invoke看起來更清晰 app = component(app)。Invoke(); } return app;}

看了一下最新的原始碼(在Asp。Net Core 5。0有一些調整)是沒有大的改動, Asp。Net Core 在Github的main分支已經進入了。Net 7。0 alpha版本了。正式。Net 6版本下月9號釋出。

///

/// Produces a that executes added middlewares。/// /// The public RequestDelegate Build(){ RequestDelegate app = context => { // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened。 // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware。 var endpoint = context。GetEndpoint(); var endpointRequestDelegate = endpoint?。RequestDelegate; if (endpointRequestDelegate != null) { var message = $“The request reached the end of the pipeline without executing the endpoint: ‘{endpoint!。DisplayName}’。 ” + $“Please register the EndpointMiddleware using ‘{nameof(IApplicationBuilder)}。UseEndpoints(。。。)’ if using ” + $“routing。”; throw new InvalidOperationException(message); } context。Response。StatusCode = StatusCodes。Status404NotFound; return Task。CompletedTask; }; //這裡改為迴圈倒序,減少使用Reverse反轉List for (var c = _components。Count - 1; c >= 0; c——) { app = _components[c](app); } return app;}

如果您覺得對您有用的話,可以點個贊或者加個關注,歡迎大家一起進行技術交流