ASP.NET Core實(shí)現(xiàn)中間件的幾種方式
前言
ASP.NET Core 中 HTTP 管道使用中間件組合處理的方式,
換句人話(huà)來(lái)說(shuō),
對(duì)于寫(xiě)代碼的人而言,一切皆中間件.
業(yè)務(wù)邏輯/數(shù)據(jù)訪(fǎng)問(wèn)/等等一切都需要以中間件的方式來(lái)呈現(xiàn).
那么我們必須學(xué)會(huì)如何實(shí)現(xiàn)自定義中間件 這里劃重點(diǎn),必考
這里我們介紹下中間件的幾種實(shí)現(xiàn)方式...
匿名函數(shù)
通常新建一個(gè)空的 ASP.NET Core Web Application,項(xiàng)目名字無(wú)所謂啦
在啟動(dòng)類(lèi)里可以看到這么一句:
// Startup.cs// ...app.Run(async (context) =>{ await context.Response.WriteAsync("Hello World!");});// ...這就是一個(gè)匿名函數(shù)實(shí)現(xiàn)的中間件,雖然內(nèi)容比較少.
可以看到通過(guò)匿名函數(shù)實(shí)現(xiàn)的中間件是內(nèi)嵌在啟動(dòng)類(lèi)文件中的,因此通常也叫做內(nèi)聯(lián)中間件
接下來(lái),我們通過(guò)匿名函數(shù)來(lái)實(shí)現(xiàn)內(nèi)聯(lián)中間件,以便加深理解.
然后修改啟動(dòng)類(lèi)代碼如下:
// Startup.csusing Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.DependencyInjection;using System;namespace WebApplication1{ public class Startup {public void ConfigureServices(IServiceCollection services){}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) {app.UseDeveloperExceptionPage(); } // 使用匿名函數(shù)實(shí)現(xiàn)一個(gè)內(nèi)聯(lián)中間件 app.Use(async (context, next) => {throw new NotImplementedException("一個(gè)使用匿名函數(shù),但未實(shí)現(xiàn)具體內(nèi)容的內(nèi)聯(lián)中間件"); }); app.Run(async (context) => {await context.Response.WriteAsync("Hello World!"); });} }}這里我們?cè)?app.Run 之前使用 app.Use 添加一個(gè)匿名函數(shù)實(shí)現(xiàn)的內(nèi)聯(lián)中間件,按照中間件的注冊(cè)順序,當(dāng)發(fā)起請(qǐng)求時(shí),會(huì)拋出一個(gè)異常 NotImplementedException("一個(gè)使用匿名函數(shù),但未實(shí)現(xiàn)具體內(nèi)容的內(nèi)聯(lián)中間件")
我們 F5 啟動(dòng)下,看看頁(yè)面

嗯,符合預(yù)期.
我們?cè)賮?lái)調(diào)整下啟動(dòng)類(lèi),代碼如下:
using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.DependencyInjection;namespace WebApplication1{ public class Startup {public void ConfigureServices(IServiceCollection services){}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) {app.UseDeveloperExceptionPage(); } // 使用匿名函數(shù)實(shí)現(xiàn)一個(gè)內(nèi)聯(lián)中間件 app.Use(async (context, next) => {// 這里不對(duì) request 做任何處理,直接調(diào)用下一個(gè)中間件await next.Invoke(); }); app.Run(async (context) => {await context.Response.WriteAsync("Hello World!"); });} }}這里我們?cè)?app.Run 之前使用 app.Use 添加一個(gè)匿名函數(shù)實(shí)現(xiàn)的內(nèi)聯(lián)中間件,該中間件沒(méi)有對(duì) request 做任何處理,只是一個(gè)空的空間件,按照中間件的注冊(cè)順序,當(dāng)發(fā)起請(qǐng)求時(shí),頁(yè)面應(yīng)該顯示 Hello World!.
我們 F5 啟動(dòng),看看效果

嗯,符合預(yù)期.
個(gè)人覺(jué)得:匿名函數(shù)不是很直觀(guān),但是用內(nèi)聯(lián)的方式可以快速開(kāi)始一些開(kāi)發(fā),不用新建一個(gè)中間件類(lèi),不用專(zhuān)門(mén)想個(gè)不一樣的名字,小場(chǎng)景下是非常方便實(shí)用的
實(shí)現(xiàn)接口
通過(guò)實(shí)現(xiàn)接口 IMiddleware 編寫(xiě)自定義中間件,這是一種強(qiáng)類(lèi)型的方式,我們需要必須強(qiáng)制按照接口的定義來(lái)實(shí)現(xiàn).
IMiddleware
接口 IMiddleware 定義如下:
using System.Threading.Tasks;namespace Microsoft.AspNetCore.Http{ public interface IMiddleware {Task InvokeAsync(HttpContext context, RequestDelegate next); }}可以看到接口 IMiddleware 的命名空間是 Microsoft.AspNetCore.Http,需要實(shí)現(xiàn)的方法是InvokeAsync(),看起來(lái)不算太復(fù)雜, 嗯,看起來(lái)不算太復(fù)雜
嗯,重新開(kāi)始,我們新建一個(gè)空的 ASP.NET Core Web Application
然后我們通過(guò)實(shí)現(xiàn)接口的方式來(lái)自定義一個(gè)中間件,代碼如下:
// 新建類(lèi) MyMiddleware.csusing Microsoft.AspNetCore.Http;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace WebApplication1{ public class MyMiddleware : IMiddleware {public Task InvokeAsync(HttpContext context, RequestDelegate next){ throw new NotImplementedException();} }}按照上面實(shí)現(xiàn)的中間件 MyMiddleware,在執(zhí)行時(shí)應(yīng)該會(huì)拋出 NotImplementedException.
使用接口實(shí)現(xiàn)的中間件需要在先在服務(wù)容器中注冊(cè)
// Startup.csusing Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.DependencyInjection;namespace WebApplication1{ public class Startup {public void ConfigureServices(IServiceCollection services){ // 在服務(wù)容器中注冊(cè)自定義中間件 services.AddSingleton<MyMiddleware>();}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) {app.UseDeveloperExceptionPage(); } // 使用 UseMiddleware() 把自定義中間件添加到管道中 app.UseMiddleware<MyMiddleware>(); app.Run(async (context) => {await context.Response.WriteAsync("Hello World!"); });} }}然后 F5 啟動(dòng),頁(yè)面上可以看到如下結(jié)果:

符合我們上面的預(yù)期,拋出了一個(gè) NotImplementedException.
然后我們改造下 MyMiddleware 中間件
// MyMiddleware.csusing Microsoft.AspNetCore.Http;using System.Threading.Tasks;namespace WebApplication1{ public class MyMiddleware : IMiddleware {public async Task InvokeAsync(HttpContext context, RequestDelegate next){ // 這里不對(duì) request 做任何處理,直接調(diào)用下一個(gè)中間件 await next(context);} }}這里相當(dāng)于我們實(shí)現(xiàn)了一個(gè)叫做 MyMiddleware 的中間件,但是并沒(méi)有對(duì)請(qǐng)求進(jìn)行任何處理,頁(yè)面上應(yīng)該正常顯示 Hello World! 字符串.
然后我們 F5 啟動(dòng)看看

嗯...符合預(yù)期.
個(gè)人覺(jué)得:這種方式最符合面向?qū)ο蟮奶匦?也符合面向接口的原則,少一些難以理解的魔法,反而有助于理解.
約定方式
編程世界有這么一句話(huà),叫"約定大于配置".
那么編寫(xiě)中間件的約定是什么呢?
重新開(kāi)始,新建一個(gè)空的 ASP.NET Core Web Application
然后新建一個(gè)類(lèi),類(lèi)名叫做 MyMiddleware 好了,代碼如下:
// MyMiddleware.csusing Microsoft.AspNetCore.Http;using System;using System.Threading.Tasks;namespace WebApplication1{ public class MyMiddleware {// 1. 需要實(shí)現(xiàn)一個(gè)構(gòu)造函數(shù),參數(shù)為 RequestDelegatepublic MyMiddleware(RequestDelegate next){}// 2. 需要實(shí)現(xiàn)一個(gè)叫做 InvokeAsync 方法public async Task InvokeAsync(HttpContext context){ throw new NotImplementedException("這是一個(gè)按照約定方式編寫(xiě)的中間件,但未實(shí)現(xiàn)具體內(nèi)容");} }}約定的內(nèi)容,就是滿(mǎn)足2個(gè)需要...不滿(mǎn)足需要?jiǎng)t異常.
然后我們把這個(gè)中間件,注冊(cè)到管道中,以便使用
// Startup.csusing Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.DependencyInjection;namespace WebApplication1{ public class Startup {public void ConfigureServices(IServiceCollection services){}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) {app.UseDeveloperExceptionPage(); } // 注冊(cè)自定義中間件 // 注冊(cè)順序=1 app.UseMiddleware<MyMiddleware>(); app.Run(async (context) => {await context.Response.WriteAsync("Hello World!"); });} }}然后 F5 啟動(dòng),來(lái)看看效果

嗯,符合預(yù)期.
然后我們來(lái)調(diào)整下中間件,讓請(qǐng)求能正常響應(yīng)輸出 Hello World!
using Microsoft.AspNetCore.Http;using System;using System.Threading.Tasks;namespace WebApplication1{ public class MyMiddleware {private readonly RequestDelegate _next;// 需要實(shí)現(xiàn)一個(gè)構(gòu)造函數(shù),參數(shù)為 RequestDelegatepublic MyMiddleware(RequestDelegate next){ _next = next;}// 需要實(shí)現(xiàn)一個(gè)叫做 InvokeAsync 方法public async Task InvokeAsync(HttpContext context){ // 不處理任何 request, 直接調(diào)用下一個(gè)中間件 await _next.Invoke(context);} }}然后 F5 啟動(dòng),看看效果

嗯,符合預(yù)期.
個(gè)人覺(jué)得:只能說(shuō)一句,約定方式是目前用的最多的方式...
End
寫(xiě)在最后
Tips: 有些內(nèi)容可能看起來(lái)還是不太容易理解,至少當(dāng)下你是很難理解的,但是套路就在哪里,好比1+1=2,你知道1+1為什么=2么?但你一定會(huì)算會(huì)用1+1=2...
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章:
1. ASP.NET Core 依賴(lài)注入生命周期示例詳解2. ASP.NET Core按用戶(hù)等級(jí)授權(quán)的方法3. ASP.Net Core(C#)創(chuàng)建Web站點(diǎn)的實(shí)現(xiàn)4. asp.net core服務(wù)限制堆內(nèi)存大小的操作方法5. Java生成中間logo的二維碼的示例代碼6. ThinkPHP6使用JWT+中間件實(shí)現(xiàn)Token驗(yàn)證實(shí)例詳解7. AspNetCore中的中間件詳解8. ASP.Net Core對(duì)USB攝像頭進(jìn)行截圖9. 理解ASP.NET Core 配置系統(tǒng)10. 如何使用ASP.NET Core 配置文件

網(wǎng)公網(wǎng)安備