.NET Core开发实战(第21课:中间件:掌控请求处理过程的关键)--学习笔记(下)...
21 | 中間件:掌控請(qǐng)求處理過程的關(guān)鍵
如果在 Map 的時(shí)候邏輯復(fù)雜一點(diǎn),不僅僅判斷它的 URL 地址,而且要做特殊的判斷的話,可以這么做把判斷邏輯變成一個(gè)委托
我們要判斷當(dāng)我們的請(qǐng)求地址包含 abc 的時(shí)候,輸出 new abc
app.MapWhen(context => {return context.Request.Query.Keys.Contains("abc"); }, builder => {builder.Run(async context =>{await context.Response.WriteAsync("new abc");}); });啟動(dòng)程序,沒有任何輸出
當(dāng)我們?cè)谀J(rèn)啟動(dòng)地址后面輸入 ?abc=1 的時(shí)候,可以看到輸出了 new abc
這里用到了一個(gè) Run 的方法,上一節(jié)用到的是 Use 方法
app.Map("/abc", abcBuilder => {abcBuilder.Use(async (context, next) =>{//await context.Response.WriteAsync("Hello");await next();await context.Response.WriteAsync("Hello2");}); });Run 和 Use 的區(qū)別是什么呢?
Use 是指我們可以像注冊(cè)一個(gè)完整的中間件一樣,將 next 注入進(jìn)來,我們可以去決定是否執(zhí)行后續(xù)的中間件
Run 的含義就表示我們這里就是中間件執(zhí)行的末端,也就不在執(zhí)行后面的中間件了,在這里將返回請(qǐng)求
那我們?nèi)绾蜗?UseRouting UseEndpoints 一樣來設(shè)計(jì)我們自己的中間件呢?
這里定義好了一個(gè) MyMiddleware
namespace MiddlewareDemo.Middlewares {class MyMiddleware{RequestDelegate _next;ILogger _logger;public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context){using (_logger.BeginScope("TraceIdentifier:{TraceIdentifier}", context.TraceIdentifier)){_logger.LogDebug("開始執(zhí)行");await _next(context);_logger.LogDebug("執(zhí)行結(jié)束");}}} }定義中間件是用了一個(gè)約定的方式,中間件的類包含一個(gè)方法 Invoke 或者 InvokeAsync 這樣一個(gè)方法,它的返回是一個(gè) Task,入?yún)⑹且粋€(gè) HttpContext,實(shí)際上可以理解成與中間件的委托是一樣的,只要我們的類包含這樣一個(gè)方法,就可以把它作為一個(gè)中間件注冊(cè)進(jìn)去,并被框架識(shí)別到
這里還定義了一個(gè) MyBuilderExtensions
namespace Microsoft.AspNetCore.Builder {public static class MyBuilderExtensions{public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app){return app.UseMiddleware<MyMiddleware>();}} }把我們的中間件注冊(cè)進(jìn)去,這個(gè)方法就是 UseMyMiddleware
通過這樣的定義,我們就可以使用自己的中間件
app.UseMyMiddleware();啟動(dòng)程序,輸出如下:
控制臺(tái)輸出
dbug: MiddlewareDemo.Middlewares.MyMiddleware[0]=> RequestPath:/weatherforecast RequestId:0HLU50UEM3M9F:00000001, SpanId:|77f92fe8-4a6d800968327989., TraceId:77f92fe8-4a6d800968327989, ParentId: => TraceIdentifier:0HLU50UEM3M9F:00000001開始執(zhí)行 dbug: MiddlewareDemo.Middlewares.MyMiddleware[0]=> RequestPath:/weatherforecast RequestId:0HLU50UEM3M9F:00000001, SpanId:|77f92fe8-4a6d800968327989., TraceId:77f92fe8-4a6d800968327989, ParentId: => TraceIdentifier:0HLU50UEM3M9F:00000001執(zhí)行結(jié)束網(wǎng)頁控制器輸出
[{"date":"2020-03-11T23:30:55.3411696+08:00","temperatureC":20,"temperatureF":67,"summary":"Warm"},{"date":"2020-03-12T23:30:55.3417863+08:00","temperatureC":52,"temperatureF":125,"summary":"Bracing"},{"date":"2020-03-13T23:30:55.3417916+08:00","temperatureC":-3,"temperatureF":27,"summary":"Mild"},{"date":"2020-03-14T23:30:55.341792+08:00","temperatureC":35,"temperatureF":94,"summary":"Balmy"},{"date":"2020-03-15T23:30:55.3417923+08:00","temperatureC":37,"temperatureF":98,"summary":"Sweltering"}]Hello2如果要實(shí)現(xiàn)一個(gè)斷路器,就是不執(zhí)行后續(xù)邏輯,注釋掉一行
_logger.LogDebug("開始執(zhí)行");//await _next(context);_logger.LogDebug("執(zhí)行結(jié)束");啟動(dòng)程序,頁面不會(huì)輸出任何內(nèi)容,只會(huì)在控制臺(tái)打印出中間件的執(zhí)行過程,后續(xù)的控制器不會(huì)執(zhí)行
這樣就實(shí)現(xiàn)了一個(gè)斷路器,也就意味著可以使用自己的中間件做請(qǐng)求的控制,而且時(shí)非常靈活的控制
在使用中間件的過程中,需要非常注意的是注冊(cè)中間件的順序,這些順序就決定了中間件執(zhí)行的時(shí)機(jī),某些中間件會(huì)是斷路器的作用,某些中間件會(huì)做一些請(qǐng)求內(nèi)容的處理
還有一個(gè)比較關(guān)鍵的要點(diǎn)是指應(yīng)用程序一旦開始向 Response write 的時(shí)候,后續(xù)的中間件就不能再去操作它的 header,這一點(diǎn)是需要注意的
可以通過 Context.Response.HasStarted 來判斷是否已經(jīng)開始向響應(yīng)的 body 輸出內(nèi)容,一旦輸出了內(nèi)容,就不要再操作 header
總結(jié)
以上是生活随笔為你收集整理的.NET Core开发实战(第21课:中间件:掌控请求处理过程的关键)--学习笔记(下)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 这些年我对微服务的理解
- 下一篇: 200行代码,7个对象——让你了解ASP