练习 - 创建自定义中间件
开发人员可以创建自定义中间件组件,以向 ASP.NET Core 应用中添加功能。 自定义中间件可以插入中间件管道中的任何位置,并可以与内置中间件组件一起使用,如本例中所示:
你公司的网络运营团队正在排查生产环境中的性能问题。 你的团队负责人让你实现一些功能,以更好地支持应用的实时监视。 该应用应将请求详细信息记录到控制台。 对于每个请求,它应记录请求方法、路径和响应状态代码。
在本练习中,你将创建一个自定义中间件组件,用以将请求详细信息记录到控制台。
添加自定义中间件
让我们修改现有的 ASP.NET Core 应用,以包含用于将请求详细信息记录到控制台的自定义中间件。
打开 Program.cs 文件(如果尚未打开)。
紧接在
app.Run()
之前,插入以下代码:app.Use(async (context, next) => { Console.WriteLine($"{context.Request.Method} {context.Request.Path} {context.Response.StatusCode}"); await next(); });
在上述代码中:
-
app.Use()
向管道添加一个自定义中间件组件。 该组件采用一个HttpContext
对象和一个RequestDelegate
对象作为参数。 - delegate 将请求方法、路径和响应状态代码写入到控制台。
-
await next()
调用管道中的下一个中间件组件。
-
测试更改
按 Ctrl+Shift+F5 重新生成并重启应用。
当浏览器窗口打开时,请注意根 URL 会显示“欢迎使用 Contoso!”
将
/history
添加到 URL,然后按 Enter。 浏览器将重定向到/about
页。在 Visual Studio Code 中,按 Ctrl+Shift+P 打开命令面板。 搜索并选择“调试控制台:聚焦到“调试控制台”视图”,切换到底部面板中的“调试控制台”选项卡。 注意以下行:
GET / 200 GET /about 200
对于每个请求,控制台输出会显示请求方法、路径和响应状态代码。 第一行显示了对根 URL 的请求,第二行显示了对
/about
页的请求。注意
浏览器可能还会请求
/favicon.ico
。 这是对网站图标的标准请求,可以忽略。请让应用保持运行状态以完成下一个练习。
更改中间件的顺序
应用似乎正常工作,但存在问题。 你请求了 /history
页,但控制台输出没有显示它。 之所以发生此行为,是因为用于记录请求详细信息的自定义中间件组件是在 URL 重写器中间件之后添加的。 URL 重写器中间件将请求从 /history
重定向到 /about
并发送响应,自定义中间件组件看不到请求。 让我们来解决此问题。
将你添加的
app.Use()
行移动到app.UseRewriter()
行的正前方。完整的 Program.cs 文件应如下所示:
using Microsoft.AspNetCore.Rewrite; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.Use(async (context, next) => { Console.WriteLine($"{context.Request.Method} {context.Request.Path} {context.Response.StatusCode}"); await next(); }); app.UseRewriter(new RewriteOptions().AddRedirect("history", "about")); app.MapGet("/", () => "Hello World!"); app.MapGet("/about", () => "Contoso was founded in 2000."); app.Run();
现在,自定义中间件组件添加到了 URL 重写器中间件之前。 自定义中间件组件在 URL 重写器中间件处理请求并重定向请求之前记录请求详细信息。
再次重启应用,并像以前一样对其进行测试。 这一次, 调试控制台 输出应包含页面
/history
的请求。GET / 200 GET /history 200 GET /about 200
控制台输出现在会在重定向到
/history
页面之前显示对/about
页面的请求。
修复状态代码
该应用几乎已准备就绪,但还有一个问题。 控制台输出中的状态代码始终为 200,即使应用重定向了请求也是如此。
/history
请求的状态代码应为 302 重定向。 发生此行为是因为处理中间件组件的顺序存在另一个问题。
自定义中间件组件将详细信息记录到控制台,然后调用 await next()
来传递给下一个中间件组件。 问题是,StatusCode
对象的 Response
属性是在终端中间件组件启动响应后设置的。 让我们更改代码以修复此问题。
在你添加的委托中,将
Console.WriteLine()
行移动到await next()
行之后。更新后的代码应如下所示:
app.Use(async (context, next) => { await next(); Console.WriteLine($"{context.Request.Method} {context.Request.Path} {context.Response.StatusCode}"); });
现在,自定义中间件组件将在终端中间件组件设置响应状态代码后记录请求详细信息。
重启并再次测试
/history
请求。 调试控制台输出现在应显示正确的状态代码。GET / 200 GET /history 302 GET /about 200