我们将原有ASP.NET应用升级到ASP.NET Core的过程中,会遇到一个新的概念: 中间件。
中间件是ASP.NET Core全新引入的概念。 中间件是一种装配到应用管道中以处理请求和响应的软2 8 ( m件。 每个组件:
- 选择是否将请求传递到管} ! . C ;道中的下一个组件。
- 可在管道中的下一个k 7 9 A X r P 6 0组件` g 5 X a a -前后执行工作。
单独看以上中间件的定义,一个很直观 P D V C n k的感觉:中间件C | ] c是HTTP请求管道中的一层层的AOP扩展。
在} $ / 5 h n r展开介绍中间件之前M 2 s B p,我们先回顾一下ASP.NET中HttpHandler和_ 2 v f +HttpModule的处理方式。
一、ASP.NET中HttpHandler和HttpModule
先看一张图:
上图中有两个概念HttpHandlW k 6 Y m * [ 7 %er和HttpModule,其中:
HttpI % T i ]Handler 用 . 9于处理具有给定文件名y r * c o G或扩展名的请求。比如上图中的.report类的请求,同时,任何一个HttpHandler都需: = ? 3 y要实现接口IHttpHandler,都需要在Web.Config配置文件中注册使用。
HttpModule 用于处理每个请求调用,比如上图中的Authorization Module,每个Http请求都会经过HttpModul$ p @ & A w l r Fe的处理。通过HttpModule可7 e T ; `以中断Http请求,可以自定义HttpResponse返回。同时,任何一个HttpModule都需要实现接口IHttpModQ K q y W 7 X Z Xule,H k / b c t D都需要在Web.Config配置文件中注册使用。
ASP.NET Core引Y 6 T l 9入了中间件来实现上面2种Http请求处理扩展。ASP.NET Core中间件和 ASP.NET HttpHandler HttpModule有什么区别?
二、ASP.NET Core中间件和 ASP.NET HttpHandler HttpModule的区别
1. 中间件比Http6 S p 5Ha- f l * ~ 7 o 9ndler、HttpModule更简单
- \"模块\"、\"处理程序\"、\" Global.asax.cs \"、 \"WEB.CONFIG\" (IIS 配置除外)和 \"应用程序生命周期\" 消失
- 中间件已使用HttpHandler HttpModule的角色
- 中间件使用代码而不 是在 web.config 中进行配置
- 通过管道分支,可以将请求发送到特定的中间件,不仅可以基于 URL,B ^ $ V P还可以发送到请求标头、查询字符串等。
2. 中间件类似于HttpModule
- 处理每个请求调用
- 可以实现Http请求中间和继续
- 能够创建自定义的HttpResponse
3. 中间件和HttpModule9 k Z s j k l按不同的顺序处理
- 中间件的顺序取决于它们插入请求管道的顺序,而模块的顺序主要基于应用程序生命周期事件
- 中间件中H/ $ ) & - D W #ttp响应的顺序与Http请求的顺序相反,而对于Http6 7 S { # ^ D 8Module,请求和响应E O 0 h x , g的顺序是相同的。
三 、ASP.NET Core中间( b m q ]件的设计原理
ASP.NET Core 请求 K a K . %管道包含+ o 2 * D P t Y %一系列请求委托,依次调用。 下图j L A 0 6 e | U演示了这一概念。 沿黑色箭{ 7 { Z # P头执行j h k E %。
每个请求_ } K t p b & s s委托(中间件)都可以在下一个请求委托(中间件)之前和之后执行操作。中间F R 4 d :件中的 异常处理委托应该在管道的早期被处理,这样就可以捕获在管道h 8 R 6后期发8 9 _ D @ G生的异常。
在Startup.Configure 方法中添加中间件组件的顺序定义了针对请求调用这些中间件的顺序,以及响应的相反顺序。 这个顺序对于安全性、性能和功能非常重要。
看一段示例代码:
public void Confc 0 Digure(IApplicationBuilder app, IWe` W qbHostEnvironment env)
{
if (env.IsDevelopmr K b ~ { Oent())
{
app.UseDeveR ] d K q z AloperException/ b x z cPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler(U H t n . :\"/Error\");
app.UseHsts(I T ^);
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// ap[ H , fp.UseCookiePoX s 6 D p 4licy();
app.UseRl k z * bouting();
// app.U4 [ `seRequestLocalizationg c x / M $();
// app.UseCors();
app.d u - _ k #UseAuthentict c M 6 q f ; .ation()1 [ l R F # C l l;
app.UseN 7 F . VAuthoriz4 + |ation();
// app.Ua ; 3 @ 5 o nseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapW | c 9 = -ControllerRoute(v s [ R
name: \"default\",
pattern: 5 U r G @ A / W\"{controller=Home}/{action=Index}/{id?}\");
});
}
上述代码中每个中间件扩展方法都通过 Microsoft.AspNetCore.Builder 命名空间在 IApplicationBuilde1 5 [ E T J t s qr 上公开。
app.Use***都是各种常用的内置中间件。比如:
1. 异常处理类中间件。如上述代码中:
当应用在开发环境中运行时:异常显示页中间件 (UseDeveloperExceptionP0 q w . k /age) 报告应用运行时错误。数据库错误页中间件报告数据库运行时错误。(app.UseDatabaseErrorPage();)
当应用在生产环境中运行时:N T x u p j / ]异常处理程序中间件 (U 0 0 k U n |seEX R v t d w 1xceptionHandler) 捕获以下中间件中引发的异常。T0 c 4 ^ C l QTP 严格传输安全协议 (HSTS) 中间件 (UseHsts) 添加 Strict-Transport-Security 标头。
2. HTTPS 重定向中间件 (UseHh G k % F fttpsRedirection) 将 HTTP 请求重定向到 HTTPS。
3. 静态文件中间件 (UseStaticFiles) 返回静态文件,并简化进一步请求处0 ( J 2 ] ! g P a理。
4. Coou v ] m = U e # tkie 策略中间件 (UseCookiePolicy) 使应用符合欧盟一般数据: a = O [ P | Q保护条例 (GDPR) 规定。
5. 用于路由请0 E 0求的路由中间件 (UseRouting)。
6. 身份验证中w z } l F间件 (UseAuthentication)9 R m 3 [ ] 尝试对用户进行身份验G l 9 Y证,然后才会允许用户访问安全资源。
7. 用于授权用户访问安全资源的授权中间件 (UseAuthorization)。
8. 会话中间件 (Us . :eSession) 建立和维护会话状态。 如果应用使用会话状态,请在 Cook/ C qie 策略中间件之后和 MVC 中间件之前调用会话中间件。
9.c ~ z e 用于将 Razor Pages 终结点添加到请求管道的终结点路由中间件(带有 MapRazorPages 的 UseEndpoints)。
10. 对于单页应用程序 (SPA),SPA 中间件 UseSpaStaticFiles 通常是中间件管道中的最后一个。 SPA 中间件处于最后的作用是:允许所- - ? H O J %有其他中间件首先响应匹配的请求。允许具有客户端侧路由的 SPA 针对服务器应用无法识别的所有路由运行。
还有很多其他的内置中间件,可以参考链接: https://docs.m4 X k ` L D Licrosoft.com/en-us/aspnet/core/fundamentals/middX q Uleware/?view=aspnetcore-3.0 。如下图,
了解了ASP.NET Core内置的中间件之后,我们可能需要自定义一些中间件,比如说原有的ASP.NET HttpModule和HttpHandler.
接下来第四部分,我们继续示例:
四 、自定义中~ s g o &间件
将已有HttpModule用自定义中间件实现
先看一下原有HttpModule的一个实现:
/// <summary>
/// 自定义HTTP扩展模块
/// </summary>
public class CustomerHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{e F _
context.BeginRequest += Context_BeginRequest;
}
private void Context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApp1 2 _ 8 T | ] r (lication)sender- I * W c / ,;
// Do s) % domething
}
public void Dispose()
{
}
}
迁移到中间! 2 J A F C P件实现:
/// <summary>
/// 自定义中间件
/// </summary>
public class CustomerMiddleware
{
private readonly Rec R m B n H r /questDelegate _next;
public CustomerMiddleware(RequestDelegate next)
{
_next = nex? } Y -t;
}S F E J &
public async Task Invoke(HttpContext context)
{
// Doo k G K something with contM H p Q S e H Zex t p f k b $ o St ne} E o R )ar the beginning of requestj D s C processing.
await _~ : &next.In H d p : E Dnvoke(context);
// Clean up.
}
}
同时增加IApplicatW Z o 3 f * @ionBuilder的一个扩展方法:
public st_ f [ F l 9 t ? Ratic IApplicationBx b e @ %uilder UseCustomerMiddleware/ } 6(this IApplicationBuildV D _ 5 E 5er builder)
{
return bu. 6 ilder.UseMiddleware<Cusg s ( R B ; _ K qtomerMiddlewa3 H t y *re>();
}
Startup中使用这个中间件:
app.UseCustomerMiddlewares();
以上是对ASP.NET Core中中间件的技术由来整理和使用分享。