定制.NET 6.0的Middleware中间件

2022-12-30 0 925

我们好,我是周瑜洪,谢谢您的写作,就要定期和你撷取心得体会,期望我的该文能正式成为你高速成长马路上的石底庄,让他们一同科技化。

在责任编辑中,他们将自学开发工具,和怎样采用它更进一步订制插件。他们将加速自学开发工具的基本知识,接着深入探讨怎样采用它做的许多特定事。

责任编辑囊括的主轴主要包括:

开发工具概要

撰写自订开发工具

开发工具的发展潜力

怎样采用开发工具

结语所在的边线,如下表所示图右图:

定制.NET 6.0的Middleware中间件

控制技术预备

他们采用控制面板、shell或Bash终端产品先建立两个ASP.NET Core MVC插件,接着转换到组织工作产品目录:

dotnet new web -n MiddlewaresDemo -o MiddlewaresDemo

接着用VS关上工程项目:

cd MiddlewaresDemo code .

注意在.NET 6.0中,web工程项目模板发生了变化。Microsoft引入了minimal API,工程项目模板默认采用minimal API。

开发工具概要

大多数人可能已经知道开发工具是什么,但有些人可能不知道,即使你已经在采用ASP.NET Core有一段时间了。他们一般不需要详细了解开发工具实例,因为它们大多隐藏在扩展方法后面,例如UseMvc()、UseAuthentication()、UseDeveloperExceptionPage()等。每次在Configure方法中,他们默认将隐式地采用至少两个或更多个开发工具组件。

开发工具组件是处理请求管道的一段代码。他们可以将请求流程想象成一串管道,每次请求调用,都会返回两个响应。开发工具负责建立回声——它操纵请求上下文,加工处理、叠加逻辑、丰富信息。

定制.NET 6.0的Middleware中间件

开发工具组件按配置顺序执行。配置的第两个开发工具组件是第两个执行的组件。他们可以把开发工具看成回旋镖,出去的时候第两个执行,回来的时候最后两个执行。

在ASP.NET Core web插件,如果客户端请求的是图像或任何其他静态文件,StaticFileMiddleware将负责查找该资源,如果找到该资源,则返回该资源。如果没有,这个开发工具除了调用下两个之外什么都不做。

MvcMiddleware组件检查请求的资源,将其映射到已配置的路由,执行控制器,建立视图,并返回HTML或Web API结果。如果MvcMiddleware没有找到匹配的控制器,它无论怎样都会返回两个结果——通常是两个404状态的结果,这就是为什么MvcMiddleware是最后配置的开发工具。

异常处理开发工具通常是配置的第一批的开发工具之一,不是因为它是第两个执行的,而是因为它是最后两个执行的。异常处理验证结果,并以客户端友好的方式在浏览器中显示可能的异常。以下过程描述了运行时发生的500错误状态:

var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet(“/”, () => “Hello World!”); app.Run();

在ASP.NET Core 6.0,Microsoft引入了minimal API,它简化了应用配置,并隐藏了许多默认配置,比如隐式的using声明,因此,在头部他们看不到任何using语句,以上就是他们看到的ASP.NET Core 6.0中的Program.cs 文件内容。在这里,lambda开发工具绑定到默认路由,只有一句简单的“Hello World!”响应流。这个特定的开发工具会终止管道并返回响应内容。因此,它是最后两个运行的开发工具。

下面他们把app.MapGet()做个替换,如下表所示右图:

app.Use(async (context, next) =>{ await context.Response.WriteAsync(“===”); await next(); await context.Response.WriteAsync(“===”); }); app.Use(async (context, next) => { await context.Response.WriteAsync(“>>>>>> “); await next(); await context.Response.WriteAsync(” <<<<<<“);}); app.Run(async context => { await context.Response.WriteAsync(“Hello World!”); });

这里调用两个app.Use()方法,并且建立了两个lambda开发工具,除了做简单的处理外,开发工具还调用了它们的后继组件,每个中间件的调用链很明确很清晰。在调用下两个开发工具之前,处理实际的请求,在调用下个开发工具之后,处理响应。以上就是管道的组织工作机制。如果现在运行程序(采用dotnet run)并在浏览器中关上URL,他们应该会看到这样的纯文本结果

===>>>>>> Hello World! <<<<<<===

不知道您理解了没?如果理解了,他们往下自学,看看怎样采用这个概念向请求管道添加许多附加功能。

撰写自订开发工具

开发工具可以说是ASP.NET Core的基座,在请求期间执行的所有逻辑都基于此机制。因此,他们可以采用它向web添加自订功能。在下面案例,他们期望找出通过请求管道的每个请求的执行时间:

他们可以在调用下两个中间件之前建立并启动秒表,接着在调用下个开发工具之后停止测量执行时间,如下表所示右图:

app.Use(async (context, next) => { var s = new Stopwatch(); s.Start(); //其他操作 await next(); s.Stop(); //结束度量 var result = s.ElapsedMilliseconds; //统计耗时 await context.Response.WriteAsync($”耗时:{result} 秒。”); });

记得为System.Diagnostics添加using语句。之后,他们将经过的毫秒返回到响应流。如果您编写的开发工具组件很多,Program.cs将变得非常混乱。所以大多数开发工具组件将被撰写为独立的类,如下表所示右图:

using System.Diagnostics; public class StopwatchMiddleware { private readonly RequestDelegate _next; public StopwatchMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { var s = new Stopwatch(); s.Start(); //其他操作 await _next(context); s.Stop(); //结束度量 var result = s.ElapsedMilliseconds; //统计耗时 await context.Response.WriteAsync($”耗时:{result} 秒。”); } }

在Invoke方法中的,他们获得构造函数和当前上下文获得要执行的下两个开发工具组件。

注意:

开发工具在应用程序启动时初始化,构造函数在插件生命周期内仅运行一次。另一方面,每个请求调用一次Invoke方法。

要采用此开发工具,您可以采用两个通用的UseMiddleware方法:
app.UseMiddleware<StopwatchMiddleware>();

然而,更优雅的方法是建立两个封装此调用的扩展方法:

public static class StopwatchMiddlewareExtension { public static IApplicationBuilder UseStopwatch(this IApplicationBuilder app) { app.UseMiddleware<StopwatchMiddleware>(); return app; } }

接着就可以这样采用:

app.UseStopwatch();

这样,您可以通过请求管道向ASP.NET Core插件提供其他功能。开发工具中提供了整个HttpContext。这样,您可以采用开发工具操纵请求和响应。

例如,AuthenticationMiddleware尝试从请求中收集用户信息。如果找不到任何信息,它将通过向客户端发送特定的响应来请求信息。如果它找到,它会将其添加到请求上下文中,并以这种方式将其提供给整个插件。

开发工具的发展潜力

采用开发工具还可以做许多其他事。例如,可以将请求管道拆分为两个或多个管道,他们将在这里讨论怎样做到这一点。

采用/map分支管道

下一段代码显示了怎样基于特定路径建立请求管道的分支:

app.Map(“/map1”, app1 => { // 其他开发工具 app1.Run(async context => { await context.Response.WriteAsync(“Map Test 1”); }); }); app.Map(“/map2”, app2 => { // 其他开发工具 app2.Run(async context => { await context.Response.WriteAsync(“Map Test 2”); }); }); // 其他开发工具

/map1路径是两个特定的分支,它在内部继续请求管道,/map2与此相同。这两个map都有自己内部的开发工具配置。所有其他未指定的路径都遵循该主分支。

采用MapWhen分支管道

还有两个MapWhen方法可以根据条件分支管道,而不是根据路径分支:

public void Configure(IApplicationBuilder app) { app.MapWhen(context =>context.Request.Query.ContainsKey(“分支”), app1 => { // 其他开发工具 app1.Run(async context => { await context.Response.WriteAsync( “MapBranch Test”); }); }); //其他开发工具 app.Run(async context => { await context.Response.WriteAsync(“Hello non-Map.”); });}

采用开发工具构造条件

他们一般可以根据配置值建立条件,或者根据请求上下文的属性建立条件。在前面的示例中,他们采用了查询字符串属性作为条件。当然,你也可以采用HTTP标头、表单属性或请求上下文的任何其他属性。

如果需要,还可以嵌套map以建立子分支和孙分支。他们再看下健康检查开发工具,ASP.NET Core HealthCheck API的工作原理如下表所示:首先,它采用MapWhen指定要采用的端口,接着,它采用Map设置HealthCheck API路径(如果未指定端口则采用Map)。最后,采用了HealthCheckMiddleware。他们看下面的代码示例:

private static void UseHealthChecksCore(IApplicationBuilder app, PathString path, int? port, object[] args) { if (port == null) { app.Map(path, b => b.UseMiddleware<HealthCheckMiddleware>(args)); } else { app.MapWhen(c => c.Connection.LocalPort == port, b0 => b0.Map(path, b1 =>b1.UseMiddleware<HealthCheckMiddleware>(args))); }; }

这里,他们可以采用Map或MapWhen分别基于特定路径或特定条件提供特定的API或资源。接下来,让他们看看怎样在更新版本的ASP.NET Core中采用终止开发工具组件。

在ASP.NET Core 3.0及更高版本中采用开发工具

ASP.NET Core 3.0及更高版本,有两种新的开发工具,它们被称为UseRoutingUseEndpoints

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet(“/”, async context => { await context.Response.WriteAsync(“Hello World!”); }); }); }

第两个是采用路由的开发工具UseRouting,另两个是访问地址的UseEndpoints

这是新的端点路由。以前,路由是MVC的一部分,它只适用于MVC、Web API和基于MVC的框架。然而在ASP.NET Core 3.0及更高版本,路由不再是MVC框架中的一部分。现在,MVC和其他框架都可以被映射到特定的路由或端点。

在前面的代码段中,GET请求被映射到页面根URL。在下两个代码片段中,MVC被映射到路由模式,RazorPages被映射到基于RazorPage的特定文件结构的路由:
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute(name: “default”, pattern: “{controller=Home}/{action=Index}/{id?}”); endpoints.MapRazorPages(); });

现在已经没有UseMvc方法了,即使它仍然存在并在IApplicationBuilder对象级别上组织工作,以防止现有代码中断。现在,激活ASP.NET Core功能的方法更为精细。

Areas for MVC and web API: endpoints.MapAreaControllerRoute(…);

MVC and web API: endpoints.MapControllerRoute(…);

Blazor server-side: endpoints.MapBlazorHub(…);

SignalR: endpoints.MapHub(…);

Razor Pages:endpoints.MapRazorPages(…);

Health checks: endpoints.MapHealthChecks(…);

这些是ASP最常用的新Map方法。还有很多方法可以定义回退地址,比如将路由和HTTP方法映射到代理,和开发工具组件。你可以建立适用于所有请求的开发工具,例如StopWatchMiddleware,你也可以撰写开发工具以在特定路径或路由上组织工作,例如建立两个Map方法,以将其映射到该路由。

注意事项

不再建议在开发工具内部处理路由。相反,您应该采用新的地址路由。采用这种方法,开发工具更加通用,它可以通过单一的配置就可以在多个路由上组织工作。

重写终止开发工具

接下来,他们创建小型虚拟开发工具,将插件状态写入特定路由。在此示例中,没有自订路由处理:

namespace MiddlewaresSample; public class AppStatusMiddleware { private readonly RequestDelegate _next; private readonly string _status; public AppStatusMiddleware(RequestDelegate next, string status) { _next = next; _status = status; } public async Task Invoke(HttpContext context) { await context.Response.WriteAsync($”Hello {_status}!”); } }

他们需要做的是在IEndpointRouteBuilder对象上撰写两个扩展方法。此方法将路由模式作为可选参数,并返回IEndpointConventionBuilder对象以启用跨域资源共享(CORS)、身份验证或路由的其他条件。

现在,他们应该添加两个扩展方法,以便更容易地采用开发工具:

public static class MapAppStatusMiddlewareExtension { public static IEndpointConventionBuilder MapAppStatus(this IEndpointRouteBuilder routes, string pattern = “/”, string name = “World”) { var pipeline = routes.CreateApplicationBuilder().UseMiddleware<AppStatusMiddleware>(name).Build(); return routes.Map(pattern, pipeline).WithDisplayName(“AppStatusMiddleware”); } }

完成后,他们可以采用MapAppStatus方法将其映射到特定路线:

app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet(“/”, () => “Hello World!”); endpoints.MapAppStatus(“/status”, “Status”); });

现在,他们可以通过输入以下地址在浏览器中调用路由: http://localhost:5000/status

总结

大多数ASP.NET Core功能基于开发工具,在结语中,他们自学了开发工具的组织工作原理和怎样建立自己的开发工具组件来扩展ASP.NET框架。他们还学习了怎样采用新路由向自订的终止开发工具添加路由。

在下一章中,他们将了解ASP.NET Core中的新端点路由,它允许他们以简单灵活的方式建立自己的托管端点。

举报/反馈

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务