ASP.NET Core 中间件(Middleware)详解
原文:ASP.NET Core 中间件(Middleware)详解

本文为官方文档译文,官方文档现已非机器翻译 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1

什么是中间件(Middleware)?

中间件是组装到应用程序管道中以处理请求和响应的软件。 每个组件:

  • 选择是否将请求传递给管道中的下一个组件。
  • 可以在调用管道中的下一个组件之前和之后执行工作。

请求委托(Request delegates)用于构建请求管道,处理每个HTTP请求。

请求委托使用RunMapUse扩展方法进行配置。单独的请求委托可以以内联匿名方法(称为内联中间件)指定,或者可以在可重用的类中定义它。这些可重用的类和内联匿名方法是中间件或中间件组件。请求流程中的每个中间件组件都负责调用流水线中的下一个组件,如果适当,则负责链接短路。

将HTTP模块迁移到中间件解释了ASP.NET Core和以前版本(ASP.NET)中的请求管道之间的区别,并提供了更多的中间件示例。

使用 IApplicationBuilder 创建中间件管道

ASP.NET Core请求流程由一系列请求委托组成,如下图所示(执行流程遵循黑色箭头):

每个委托可以在下一个委托之前和之后执行操作。委托还可以决定不将请求传递给下一个委托,这称为请求管道的短路。短路通常是可取的,因为它避免了不必要的工作。例如,静态文件中间件可以返回一个静态文件的请求,并使管道的其余部分短路。需要在管道早期调用异常处理委托,因此它们可以捕获后面管道的异常。

最简单的可能是ASP.NET Core应用程序建立一个请求的委托,处理所有的请求。此案例不包含实际的请求管道。相反,针对每个HTTP请求都调用一个匿名方法。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;public class Startup
{public void Configure(IApplicationBuilder app){app.Run(async context =>{await context.Response.WriteAsync("Hello, World!");});}
}

第一个 app.Run 委托终止管道。

有如下代码:

通过浏览器访问,发现确实在第一个app.Run终止了管道。

您可以将多个请求委托与app.Use连接在一起。 next参数表示管道中的下一个委托。 (请记住,您可以通过不调用下一个参数来结束流水线。)通常可以在下一个委托之前和之后执行操作,如下例所示:

public class Startup
{public void Configure(IApplicationBuilder app){app.Use(async (context, next) =>{await context.Response.WriteAsync("进入第一个委托 执行下一个委托之前\r\n");//调用管道中的下一个委托await next.Invoke();await context.Response.WriteAsync("结束第一个委托 执行下一个委托之后\r\n");});app.Run(async context =>{await context.Response.WriteAsync("进入第二个委托\r\n");await context.Response.WriteAsync("Hello from 2nd delegate.\r\n");await context.Response.WriteAsync("结束第二个委托\r\n");});}
}

使用浏览器访问有如下结果:

可以看出请求委托的执行顺序是遵循上面的流程图的。

注意:
响应发送到客户端后,请勿调用next.Invoke。 响应开始之后,对HttpResponse的更改将抛出异常。 例如,设置响应头,状态代码等更改将会引发异常。在调用next之后写入响应体。

  • 可能导致协议违规。 例如,写入超过content-length所述内容长度。

  • 可能会破坏响应内容格式。 例如,将HTML页脚写入CSS文件。

HttpResponse.HasStarted是一个有用的提示,指示是否已发送响应头和/或正文已写入。

顺序

Startup。Configure方法中添加中间件组件的顺序定义了在请求上调用它们的顺序,以及响应的相反顺序。 此排序对于安全性,性能和功能至关重要。

Startup.Configure方法(如下所示)添加了以下中间件组件:

  1. 异常/错误处理
  2. 静态文件服务
  3. 身份认证
  4. MVC
public void Configure(IApplicationBuilder app)
{app.UseExceptionHandler("/Home/Error"); // Call first to catch exceptions// thrown in the following middleware.app.UseStaticFiles();                   // Return static files and end pipeline.app.UseAuthentication();               // Authenticate before you access// secure resources.app.UseMvcWithDefaultRoute();          // Add MVC to the request pipeline.
}

上面的代码,UseExceptionHandler是添加到管道中的第一个中间件组件,因此它捕获以后调用中发生的任何异常。

静态文件中间件在管道中提前调用,因此可以处理请求和短路,而无需通过剩余的组件。 静态文件中间件不提供授权检查。 由其提供的任何文件,包括wwwroot下的文件都是公开的。

如果请求没有被静态文件中间件处理,它将被传递给执行身份验证的Identity中间件(app.UseAuthentication)。 身份不会使未经身份验证的请求发生短路。 虽然身份认证请求,但授权(和拒绝)仅在MVC选择特定的Razor页面或控制器和操作之后才会发生。

授权(和拒绝)仅在MVC选择特定的Razor页面或Controller和Action之后才会发生。

以下示例演示了中间件顺序,其中静态文件的请求在响应压缩中间件之前由静态文件中间件处理。 静态文件不会按照中间件的顺序进行压缩。 来自UseMvcWithDefaultRoute的MVC响应可以被压缩。

public void Configure(IApplicationBuilder app)
{app.UseStaticFiles();         // Static files not compressedapp.UseResponseCompression();app.UseMvcWithDefaultRoute();
}

Use, Run, 和 Map

你可以使用UseRunMap配置HTTP管道。Use方法可以使管道短路(即,可以不调用下一个请求委托)。Run方法是一个约定, 并且一些中间件组件可能暴露在管道末端运行的Run [Middleware]方法。Map*扩展用作分支管道的约定。映射根据给定的请求路径的匹配来分支请求流水线,如果请求路径以给定路径开始,则执行分支。

public class Startup
{private static void HandleMapTest1(IApplicationBuilder app){app.Run(async context =>{await context.Response.WriteAsync("Map Test 1");});}private static void HandleMapTest2(IApplicationBuilder app){app.Run(async context =>{await context.Response.WriteAsync("Map Test 2");});}public void Configure(IApplicationBuilder app){app.Map("/map1", HandleMapTest1);app.Map("/map2", HandleMapTest2);app.Run(async context =>{await context.Response.WriteAsync("Hello from non-Map delegate. <p>");});}
}

下表显示了使用以前代码的 http://localhost:19219 的请求和响应:

请求 响应
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.

当使用Map时,匹配的路径段将从HttpRequest.Path中删除,并为每个请求追加到Http Request.PathBase

MapWhen根据给定谓词的结果分支请求流水线。 任何类型为Func<HttpContext,bool>的谓词都可用于将请求映射到管道的新分支。 在以下示例中,谓词用于检测查询字符串变量分支的存在:

public class Startup
{private static void HandleBranch(IApplicationBuilder app){app.Run(async context =>{var branchVer = context.Request.Query["branch"];await context.Response.WriteAsync($"Branch used = {branchVer}");});}public void Configure(IApplicationBuilder app){app.MapWhen(context => context.Request.Query.ContainsKey("branch"),HandleBranch);app.Run(async context =>{await context.Response.WriteAsync("Hello from non-Map delegate. <p>");});}
}

以下下表显示了使用上面代码 http://localhost:19219 的请求和响应:

请求 响应
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=1 Branch used = master

Map支持嵌套,例如:

app.Map("/level1", level1App => {level1App.Map("/level2a", level2AApp => {// "/level1/level2a"//...});level1App.Map("/level2b", level2BApp => {// "/level1/level2b"//...});});

Map也可以一次匹配多个片段,例如:

app.Map("/level1/level2", HandleMultiSeg);

内置中间件

ASP.NET Core附带以下中间件组件:

中间件 描述
Authentication 提供身份验证支持
CORS 配置跨域资源共享
Response Caching 提供缓存响应支持
Response Compression 提供响应压缩支持
Routing 定义和约束请求路由
Session 提供用户会话管理
Static Files 为静态文件和目录浏览提供服务提供支持
URL Rewriting Middleware 用于重写 Url,并将请求重定向的支持

编写中间件

中间件通常封装在一个类中,并使用扩展方法进行暴露。 查看以下中间件,它从查询字符串设置当前请求的Culture:

public class Startup
{public void Configure(IApplicationBuilder app){app.Use((context, next) =>{var cultureQuery = context.Request.Query["culture"];if (!string.IsNullOrWhiteSpace(cultureQuery)){var culture = new CultureInfo(cultureQuery);CultureInfo.CurrentCulture = culture;CultureInfo.CurrentUICulture = culture;}// Call the next delegate/middleware in the pipelinereturn next();});app.Run(async (context) =>{await context.Response.WriteAsync($"Hello {CultureInfo.CurrentCulture.DisplayName}");});}
}

您可以通过传递Culture来测试中间件,例如 http://localhost:19219/?culture=zh-CN

以下代码将中间件委托移动到一个类:

using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;namespace Culture
{public class RequestCultureMiddleware{private readonly RequestDelegate _next;public RequestCultureMiddleware(RequestDelegate next){_next = next;}public Task Invoke(HttpContext context){var cultureQuery = context.Request.Query["culture"];if (!string.IsNullOrWhiteSpace(cultureQuery)){var culture = new CultureInfo(cultureQuery);CultureInfo.CurrentCulture = culture;CultureInfo.CurrentUICulture = culture;}// Call the next delegate/middleware in the pipelinereturn this._next(context);}}
}

以下通过IApplicationBuilder的扩展方法暴露中间件:

using Microsoft.AspNetCore.Builder;namespace Culture
{public static class RequestCultureMiddlewareExtensions{public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder){return builder.UseMiddleware<RequestCultureMiddleware>();}}
}

以下代码从Configure调用中间件:

public class Startup
{public void Configure(IApplicationBuilder app){app.UseRequestCulture();app.Run(async (context) =>{await context.Response.WriteAsync($"Hello {CultureInfo.CurrentCulture.DisplayName}");});}
}

中间件应该遵循显式依赖原则,通过在其构造函数中暴露其依赖关系。 中间件在应用程序生命周期构建一次。 如果您需要在请求中与中间件共享服务,请参阅以下请求相关性。

中间件组件可以通过构造方法参数来解析依赖注入的依赖关系。 UseMiddleware也可以直接接受其他参数。

每个请求的依赖关系

因为中间件是在应用程序启动时构建的,而不是每个请求,所以在每个请求期间,中间件构造函数使用的作用域生命周期服务不会与其他依赖注入类型共享。 如果您必须在中间件和其他类型之间共享作用域服务,请将这些服务添加到Invoke方法的签名中。 Invoke方法可以接受由依赖注入填充的其他参数。 例如:

public class MyMiddleware
{private readonly RequestDelegate _next;public MyMiddleware(RequestDelegate next){_next = next;}public async Task Invoke(HttpContext httpContext, IMyScopedService svc){svc.MyProperty = 1000;await _next(httpContext);}
}

posted on 2019-07-11 22:48 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/11173306.html

ASP.NET Core 中间件(Middleware)详解相关推荐

  1. ASP.NET Core 中 HttpContext 详解与使用 |

    ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解 笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 A ...

  2. ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

    ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因 ...

  3. ASP.NET Core -中间件(Middleware)使用

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

  4. ASP.NET Core真实管道详解[1]

    ASP.NET Core管道虽然在结构组成上显得非常简单,但是在具体实现上却涉及到太多的对象,所以我们在 <ASP.NET Core管道深度剖析[共4篇]> 中围绕着一个经过极度简化的模拟 ...

  5. ASP.NET Core真实管道详解[2]:Server是如何完成针对请求的监听、接收与响应的【上】

    Server是ASP .NET Core管道的第一个节点,负责完整请求的监听和接收,最终对请求的响应同样也由它完成.Server是我们对所有实现了IServer接口的所有类型以及对应对象的统称,如下面 ...

  6. ASP.NET Core 中间件Diagnostics使用

    ASP.NET Core 中间件(Middleware)Diagnostics使用.对于中间件的介绍可以查看之前的文章ASP.NET Core 开发-中间件(Middleware). Diagnost ...

  7. ASP.NET Core中间件实现分布式 Session(转载)

    ASP.NET Core中间件实现分布式 Session 1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件 ...

  8. ASP.NET Core中间件初始化探究

    前言 在日常使用ASP.NET Core开发的过程中我们多多少少会设计到使用中间件的场景,ASP.NET Core默认也为我们内置了许多的中间件,甚至有时候我们需要自定义中间件来帮我们处理一些请求管道 ...

  9. ASP.NET Core 中间件

    1.前言 中间件(middleware)是一种装配到应用管道以处理请求和响应的组件.每个组件: ●可选择是否将请求传递到管道中的下一个组件. ●可在管道中的下一个组件前后执行工作. 请求委托(requ ...

最新文章

  1. 在Web.config或App.config中的添加自定义配置
  2. Jquery高亮显示文本中重要的关键字
  3. python100行代码-python代码行数统计 100行
  4. bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】
  5. linux虚拟化毕业设计,毕业设计(论文)-基于Linux的云校园桌面虚拟化系统的设计与实现(68页)-原创力文档...
  6. JVM中OutOFMemory和StackOverflowError异常代码
  7. 北京的林书豪,像一把小李飞刀
  8. 如何有逻辑的,简单清晰的回应问题
  9. 性能测试--jmeter结合charles,以及charles的基本使用【11】
  10. 5G概念被热炒,运营商吃相不要太难看
  11. vc mscom控件串口接收不到数据问题
  12. Android 四大组件学习之Activity六
  13. 多模态融合(三)MFAS: Multimodal Fusion Architecture Search
  14. 计算机专业游戏留学,启程:一个游戏专业留学生的第一周
  15. PDF文档如何添加图片签名
  16. Windows 2016 server NVIDIA cuda toolkit11.3 pytorch-gpu 踩坑教程
  17. mysql表analyze,ANALYZE TABLE语句如何帮助维护MySQL表?
  18. 自行实现 Onvif 对接开发模式
  19. WeDrivePlugin64_24.dll 引发win7系统不能进入桌面
  20. python 论文写作_AI基础:论文写作工具

热门文章

  1. Python偏函数应用举例-路灯指示牌
  2. tensorflow RNN循环神经网络 (分类例子)-【老鱼学tensorflow】
  3. 函数的递归调用(专题)
  4. IIS与ASP.NET管道
  5. 系统架构设计师教程学习随笔 (计算机与网络基础知识--操作系统基础知识)
  6. 如何修改数据库表或存储过程的所有者
  7. 两台服务器实现会话共享
  8. Portable PostgreSQL
  9. Java设计模式(学习整理)---策略模式
  10. 字节序及字节排序函数