ASP.NET Core實現(xiàn)中間件的幾種方式
前言
ASP.NET Core 中 HTTP 管道使用中間件組合處理的方式,
換句人話來說,
對于寫代碼的人而言,一切皆中間件.
業(yè)務(wù)邏輯/數(shù)據(jù)訪問/等等一切都需要以中間件的方式來呈現(xiàn).
那么我們必須學(xué)會如何實現(xiàn)自定義中間件 這里劃重點,必考
這里我們介紹下中間件的幾種實現(xiàn)方式...
匿名函數(shù)
通常新建一個空的 ASP.NET Core Web Application,項目名字無所謂啦
在啟動類里可以看到這么一句:
// Startup.cs
// ...
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
// ...這就是一個匿名函數(shù)實現(xiàn)的中間件,雖然內(nèi)容比較少.
可以看到通過匿名函數(shù)實現(xiàn)的中間件是內(nèi)嵌在啟動類文件中的,因此通常也叫做內(nèi)聯(lián)中間件
接下來,我們通過匿名函數(shù)來實現(xiàn)內(nèi)聯(lián)中間件,以便加深理解.
然后修改啟動類代碼如下:
// Startup.cs
using 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ù)實現(xiàn)一個內(nèi)聯(lián)中間件
app.Use(async (context, next) =>
{
throw new NotImplementedException("一個使用匿名函數(shù),但未實現(xiàn)具體內(nèi)容的內(nèi)聯(lián)中間件");
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
}這里我們在 app.Run 之前使用 app.Use 添加一個匿名函數(shù)實現(xiàn)的內(nèi)聯(lián)中間件,按照中間件的注冊順序,當發(fā)起請求時,會拋出一個異常 NotImplementedException("一個使用匿名函數(shù),但未實現(xiàn)具體內(nèi)容的內(nèi)聯(lián)中間件")
我們 F5 啟動下,看看頁面

嗯,符合預(yù)期.
我們再來調(diào)整下啟動類,代碼如下:
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ù)實現(xiàn)一個內(nèi)聯(lián)中間件
app.Use(async (context, next) =>
{
// 這里不對 request 做任何處理,直接調(diào)用下一個中間件
await next.Invoke();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
}這里我們在 app.Run 之前使用 app.Use 添加一個匿名函數(shù)實現(xiàn)的內(nèi)聯(lián)中間件,該中間件沒有對 request 做任何處理,只是一個空的空間件,按照中間件的注冊順序,當發(fā)起請求時,頁面應(yīng)該顯示 Hello World!.
我們 F5 啟動,看看效果

嗯,符合預(yù)期.
個人覺得:匿名函數(shù)不是很直觀,但是用內(nèi)聯(lián)的方式可以快速開始一些開發(fā),不用新建一個中間件類,不用專門想個不一樣的名字,小場景下是非常方便實用的
實現(xiàn)接口
通過實現(xiàn)接口 IMiddleware 編寫自定義中間件,這是一種強類型的方式,我們需要必須強制按照接口的定義來實現(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,需要實現(xiàn)的方法是InvokeAsync(),看起來不算太復(fù)雜, 嗯,看起來不算太復(fù)雜
嗯,重新開始,我們新建一個空的 ASP.NET Core Web Application
然后我們通過實現(xiàn)接口的方式來自定義一個中間件,代碼如下:
// 新建類 MyMiddleware.cs
using 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();
}
}
}按照上面實現(xiàn)的中間件 MyMiddleware,在執(zhí)行時應(yīng)該會拋出 NotImplementedException.
使用接口實現(xiàn)的中間件需要在先在服務(wù)容器中注冊
// Startup.cs
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)
{
// 在服務(wù)容器中注冊自定義中間件
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 啟動,頁面上可以看到如下結(jié)果:

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

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

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

嗯,符合預(yù)期.
個人覺得:只能說一句,約定方式是目前用的最多的方式...
End
寫在最后
Tips: 有些內(nèi)容可能看起來還是不太容易理解,至少當下你是很難理解的,但是套路就在哪里,好比1+1=2,你知道1+1為什么=2么?但你一定會算會用1+1=2...
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
asp.net 退出登陸(解決退出后點擊瀏覽器后退問題仍然可回到頁面問題)
退出登陸是再常見不過的了,先清除Session,再轉(zhuǎn)到登陸頁面2009-04-04
asp.net實現(xiàn)利用反射,泛型,靜態(tài)方法快速獲取表單值到Model的方法
這篇文章主要介紹了asp.net實現(xiàn)利用反射,泛型,靜態(tài)方法快速獲取表單值到Model的方法,結(jié)合實例形式分析了asp.net中反射,泛型,靜態(tài)方法給model賦值的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11
ASP.NET MVC制作404跳轉(zhuǎn)實例(非302和200)
本篇文章主要介紹了ASP.NET MVC制作404跳轉(zhuǎn)實例(非302和200) ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
MVC 5 第二章 MVC5應(yīng)用程序項目結(jié)構(gòu)
通過本章學(xué)習(xí),你將了解到一個MVC 5應(yīng)用程序的項目組成以及項目文件的相關(guān)信息,從而更好地架構(gòu)設(shè)計出自己的項目結(jié)構(gòu)。2014-06-06

