ASP.NET Core 中间件

ASP.NET Core 引入了一个叫做中间件的新概念。中间件只是一个组件(类),它在 ASP.NET Core 应用程序中的每个请求上执行。在经典的 ASP.NET 中,HttpHandlersHttpModules 是请求管道的一部分。中间件类似于 HttpHandlersHttpModules,两者都需要在每个请求中配置和执行。

通常,ASP.NET Core web 应用程序中会有多个中间件。它可以是通过 NuGet 添加的框架提供的中间件,也可以是您自己的定制中间件。我们可以在请求管道中设置中间件执行的顺序。每个中间件都添加或修改 http 请求,并可选地将控制权传递给下一个中间件组件。下图说明了中间件组件的执行。

中间件构建请求管道。下图说明了 ASP.NET Core 请求处理。


配置中间件

我们可以使用 IApplicationBuilder 实例在 Startup 类的 configure 方法中配置中间件。下面的实例使用 Run 方法添加了一个中间件,该方法根据每个请求返回字符串 "HelloWorld!"

  1. public class Startup
  2. {
  3. public Startup()
  4. {
  5. }
  6. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  7. {
  8. //使用 IApplicationBuilder 在这里配置中间件..
  9. app.Run(async (context) =>
  10. {
  11. await context.Response.WriteAsync("Hello World!");
  12. });
  13. // other code removed for clarity..
  14. }
  15. }

了解 Run 方法

我们使用 Run 扩展方法添加中间件。以下是 Run 方法的签名:

  1. public static void Run(this IApplicationBuilder app, RequestDelegate handler)

Run 方法是 IApplicationBuilder 上的一个扩展方法,并接受 RequestDelegate 参数。RequestDelegate 是处理请求的委托方法。以下是 RequestDelegate 签名。

  1. public delegate Task RequestDelegate(HttpContext context);

如上所述,Run 方法接受一个方法作为参数,其签名应与 RequestDelegate 匹配。因此,该方法应接受 HttpContext 参数并返回 Task。因此,您可以在 Run 方法中指定 lambda 表达式或指定函数。上面 Run 方法中指定的 lambda 表达式与下面示例中的表达式类似。

  1. public class Startup
  2. {
  3. public Startup()
  4. {
  5. }
  6. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  7. {
  8. app.Run(MyMiddleware);
  9. }
  10. private Task MyMiddleware(HttpContext context)
  11. {
  12. return context.Response.WriteAsync("Hello World! ");
  13. }
  14. }

上面的 MyMiddleware 函数不是异步的,因此将阻塞线程直到它完成执行。因此,通过使用异步和等待来提高性能和可伸缩性,使其成为异步的。

  1. // 为清晰起见,删除了其他代码
  2. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  3. {
  4. app.Run(MyMiddleware);
  5. }
  6. private async Task MyMiddleware(HttpContext context)
  7. {
  8. await context.Response.WriteAsync("Hello World! ");
  9. }

因此,上面的代码片段与下面的代码片段相同。

  1. app.Run(async context => await context.Response.WriteAsync("Hello World!") );
  2. app.Run(async (context) =>
  3. {
  4. await context.Response.WriteAsync("Hello World!");
  5. });

因此,通过这种方式,我们可以使用 Run 方法配置中间件。


配置多个中间件

大多数情况下,ASP.NET Core 应用程序中将有多个中间件组件,这些组件将按顺序执行。Run 方法添加了一个终端中间件,因此它不能调用下一个中间件,因为它将是序列中的最后一个中间件。以下命令将始终执行第一个 Run 方法,并且永远不会到达第二个 Run 方法。

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. app.Run(async (context) =>
  4. {
  5. await context.Response.WriteAsync("Hello World From 1st Middleware");
  6. });
  7. // the following will never be executed
  8. app.Run(async (context) =>
  9. {
  10. await context.Response.WriteAsync("Hello World From 2nd Middleware");
  11. });
  12. }

要配置多个中间件,请使用 use() 扩展方法。它类似于 Run() 方法,只是它包含下一个参数来调用序列中的下一个中间件。考虑以下实例。

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. app.Use(async (context, next) =>
  4. {
  5. await context.Response.WriteAsync("Hello World From 1st Middleware!");
  6. await next();
  7. });
  8. app.Run(async (context) =>
  9. {
  10. await context.Response.WriteAsync("Hello World From 2nd Middleware");
  11. });
  12. }

上面的实例将在浏览器中显示 Hello World From 1st Middleware!来自第二中间件的 Hello World!。

因此,我们可以使用 use() 方法按我们喜欢的顺序配置多个中间件。


通过 NuGet 添加内置中间件

ASP.NET Core 是一个模块化框架。通过 NuGet 安装不同的插件,我们可以在应用程序中添加所需的服务器端功能。有许多中间件插件可用于我们的应用程序。

以下是一些内置中间件:

中间件 描述
Authentication 添加身份验证支持。
CORS 配置跨源资源共享。
Routing 为 MVC 或 web 表单添加路由功能
Session 添加对用户会话的支持。
StaticFiles 添加对服务静态文件和目录浏览的支持。
Diagnostics 添加对报告和处理异常和错误的支持。

Diagnostics 中间件

让我们安装并使用 Diagnostics 中间件。Diagnostics 诊断中间件用于报告和处理 ASP.NET Core 中的异常和错误,并诊断 Entity Framework Core 迁移错误。

打开项目,添加 Microsoft.AspNetCore.Diagnostics 依赖项。等待一段时间,直到 Visual Studio 恢复包。

该软件包包括以下中间件及其扩展方法。

中间件 扩展方法 描述
DeveloperExceptionPageMiddleware UseDeveloperExceptionPage() 从管道中捕获同步和异步异常,并生成 HTML 错误响应。
ExceptionHandlerMiddleware UseExceptionHandler() 捕获异常,记录它们并在备用管道中重新执行。
StatusCodePagesMiddleware UseStatusCodePages() 检查状态代码在 400 和 599 之间的响应。
WelcomePageMiddleware UseWelcomePage() 显示根路径的欢迎页面。

我们可以调用各自的 Use* 扩展方法来在 Startup 类的 configure 方法中使用上述中间件。

让我们添加 welcomePage 中间件,它将显示根路径的欢迎页面。

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. app.UseWelcomePage();
  4. //other code removed for clarity
  5. }

这样,我们可以使用不同的 use* 扩展方法来包含不同的中间件。