- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进.
在本文中,我们将学习中间件,以及如何使用它进一步定制应用程序。我们将快速学习中间件的基础知识,然后探讨如何使用它做的一些特殊事情。 本文涵盖的主题包括:
本章所处的位置,如下图所示:
我们使用控制台、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方法中,我们默认将隐式地使用至少一个或更多个中间件组件.
中间件组件是处理请求管道的一段代码。我们可以将请求流程想象成一串管道,每次请求调用,都会返回一个响应。中间件负责创建回声——它操纵请求上下文,加工处理、叠加逻辑、丰富信息.
中间件组件按配置顺序执行。配置的第一个中间件组件是第一个执行的组件。我们可以把中间件看成回旋镖,出去的时候第一个执行,回来的时候最后一个执行.
在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 尝试从请求中收集用户信息。如果找不到任何信息,它将通过向客户端发送特定的响应来请求信息。如果它找到,它会将其添加到请求上下文中,并以这种方式将其提供给整个应用程序.
使用中间件还可以做许多其他事情。例如,可以将请求管道拆分为两个或多个管道,我们将在这里讨论如何做到这一点.
下一段代码显示了如何基于特定路径创建请求管道的分支:
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方法可以根据条件分支管道,而不是根据路径分支:
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 及更高版本,有两种新的中间件,它们被称为 UseRouting 和 UseEndpoints :
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功能的方法更为精细.
endpoints.MapAreaControllerRoute(...);
endpoints.MapControllerRoute(...);
endpoints.MapBlazorHub(...);
endpoints.MapHub(...);
endpoints.MapRazorPages(...);
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中的新端点路由,它允许我们以简单灵活的方式创建自己的托管端点.
最后此篇关于定制.NET6.0的Middleware中间件的文章就讲到这里了,如果你想了解更多关于定制.NET6.0的Middleware中间件的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有人可以给我一个更简单的以下代码的解决方案(它正在展开给定结构 0xFC :: len :: payload :: ... :: 0x0A :: 0x0D 的整数列表): object Payload
我已经在我的网站上安装了 SSL 证书,但 intermediate.crt 无法正常工作。任何 SSL 检查器(例如 GeoTrust Checker)都告诉我,缺少中间 key 。网站上已经使用了
如何让图像从这个框的中间开始? (中间纵横) 最佳答案 有几种方法可以做到这一点,如果它需要在所有浏览器(IE7+ 和其他浏览器)中工作,你需要做不同的事情来让它在某些情况下工作。 使用绝对位置
如何强制 min-height 和 vertical-align:middle 为 td 元素或其内部元素工作? 最佳答案 td 元素上的 height 等同于 min-height,因为如果需要,表
我正在尝试自动滚动到订单簿的中间行。 我有 orderBook div,其中放置了带有 orderBook 的表。该表的其中一行有一个 id middleRow。我想做的是滚动该行并将其放置在 ord
我正在尝试在 javascript 中计算绝对定位元素的 transform-origin 属性,以便它们在悬停时填充整个视口(viewport)。 我尝试通过 x 除以窗口宽度和 y 除以窗口高度来
我有休闲字符串 ' this is my string ' 是否可以删除开头和结尾的所有空格,只在单词之间留一个空格。 要选择我使用过的所有空间: SELECT regexp_replace('
我正在设法创建我的第一个复杂的 J2E 解决方案,并且在每个教程中我都发现了某种中间表的用法,如下所示: 表:用户、用户角色、角色虽然逻辑会简单地向用户表添加一个键来引用它在角色表上的角色,但为什么要
我正在寻找以下解决方案。我想定位一个图像元素,例如 在中间。所以高度是视口(viewport)的高度,宽度会自动设置,图像的中间应该在视口(viewport)宽度的中间。 我搜索的一个例子就像下面的网
我正在设计一种布局,它更像是注册用户的个人仪表板。我让它变得简单,使用基本的 2 列网格,一个用于侧边栏,一个用于主要内容。 因为,例如,80% 的网站使用将发生在一个单独的子系统中,在无 chrom
我有三个不同的 div 标签(不在彼此内部)和代码,所以它有一个把单词放在左边、中间或右边,但中心非常偏离中心。这是 HTML 代码: .desc { float: right; color:
我有以下CSS http://jsbin.com/azivip/75/edit我想让黄色的 div 高度填充蓝色和绿色 div 之间的空间。使用高度继承似乎使 div 超出了绿色 div。 有什么想法
我不得不在其父元素的中间放置一些文本。我用下面的代码实现了它: #div1 { position: relative; margin: 0; padding: 0; } #div2 {
发现一个使用合法证书(由thawte 签名)的网站,但所有浏览器都会拒绝它。我不明白为什么。thawte 的支持告诉我一个域有两个证书,然后将这个 https://www.sslshopper[dot
我正在尝试使用 OpenSSL 创建证书链,但出于某种原因,当我在我的计算机上安装我的根 CA 并尝试验证证书链时,它总是告诉我它找不到证书的颁发者.为了让事情发生,我必须安装中间 CA,这是没有意义
我看到 REST 的一大好处是依赖 HTTP 缓存。我不是在争论这个,而是完全认同这个想法。但是,我从来没有看到对中间 HTTP 缓存的更深入的解释。 如果我将 Cache-control heade
查看此图片 Facebook Messenger Android App Buttons ( MESSENGER\ACTIVE ) 我怎样才能做到这一点? 详细信息:- 带有 2px 红色边框的 di
我的任务是制作漂亮的文本,在文本中间加一条白线,如下图所示。是否可以使用 css 来实现?这是 Fiddle .container{ height:200px; width:400px;
在拉丁文字中,字母有大写和小写形式。在 Python 中,如果你想比较两个字符串而不考虑它们的大小写,你可以使用 'string'.upper() 或 'string'.lower() 将它们转换为相
我正在使用 awk 对文件进行一些文本处理。例如删除尾随空格。 awk '{gsub(/ +$/, "")} {print $0}' filename 这很好用。但是当我将输出重定向到原始文件时。它变
我是一名优秀的程序员,十分优秀!