.net 温故知新【17】:Asp.Net Core WebAPI 中间件
一、前言
到这篇文章为止,关于.NET "温故知新"系列的基础知识就完结了,从这一系列的系统回顾和再学习,对于.NET core、ASP.NET CORE又有了一个新的认识。
不光是从使用,还包括这些知识点的原理,虽然深入原理谈不上,但对于日常使用也够了,我想的是知其然,知其所以然。
在实际开发过程中可能是知道怎么使用就行,但系统学习了这些基本的框架、组件、或者说原理后,对于我们软件设计、开发、扩展和解决问题还是有帮助的。
刚好到2023新年前赶着写完,也算对自己这个系列的一个交代,实际上我平时基本不使用ASP.NET CORE,目前我主要开发桌面程序,还是用的winform。
写这个系列的初衷是想紧跟.NET的发展进程,同时储备基础知识,平时还搞一些微服务(Java)、NLP、OCR、知识图谱、前端(Vue3),只要需要反正啥都搞,没必要固执,技术只是手段,不是目的。
那么接下来就继续简单的梳理一下中间件,欢迎对这个系列拍砖!
二、中间件
中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
这个是关于中间件概念的概括,官方的概括是相当精准,那么我们就围绕管道、传递、组件来看看中间件。
请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。使用 Run、Map 和 Use 扩展方法来配置请求委托。
我们照例新建一个ASP.NET CORE Web API 项目:WebAPI_Middleware
namespace WebAPI_Middleware
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
在Program.cs 中我们看到前面部分builder是配置依赖注入的东西,这部分可以参看.net 温故知新【13】:Asp.Net Core WebAPI 使用依赖注入DI 。
app 使用Use扩展用于中间件添加到管道中
Map 基于给定请求路径的匹配项来创建请求管道分支
Run 委托始终为终端,用于终止管道。
中间件的执行顺序过程如下:

三、Map
我们将上面自动创建的东西全都删除,用Map来匹配路由,然后通过不同的代理处理请求。
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
//匹配map1 请求
app.Map("/map1", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
}));
//匹配map2 请求
app.Map("/map2", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map2 run");
});
}));
app.Run();
}
}
- 请求map1 我们输出:map1 run

- 请求map2 我们输出:map2 run

Asp.Net Core MapControllers 的扩展方法也是类似道理,用来匹配路由调用处理程序。
四、Run
在上面的 Map 后面我们使用的处理方法中 Run 用于终止管道。也就是说在该管道中如果调用了 Run 那么就直接返回了,即使你后面还添加了 Use 也不会执行。
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
Map 相当于是迎客进门,Map 上了就用指定的管道进行处理,如果没有 Map 上就调用主管道,也就是主管道上的其他中间件也会执行处理。比如我们再加一个 Run 用于没匹配上路由也输出点信息。

加了context.Response.ContentType = "text/plain; charset=utf-8"; 不然中文会乱码。

因为 Run 是终结点,那这个管道中我还想加其他处理怎么办呢,这个时候就该轮到 Use 出场了。
五、Use
用 Use 将多个请求委托链接在一起。 next 参数表示管道中的下一个委托。 可通过不调用 next 参数使管道短路。
首先我们在外面添加两个 Use,不放到 Map 中,这样的话就只有未匹配到的路由会调用
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map1 run");
});
}));
app.Map("/map2", new Action<IApplicationBuilder>((app) =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("map2 run");
});
}));
//Use1
app.Use(async (context, next) =>
{
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("第 1 个Use 开始!\r\n", Encoding.UTF8);
await next();
await context.Response.WriteAsync("第 1 个Use 结束!\r\n", Encoding.UTF8);
});
//Use2
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("第 2 个Use 开始!\r\n", Encoding.UTF8);
await next();
await context.Response.WriteAsync("第 2 个Use 结束!\r\n", Encoding.UTF8);
});
//结束管道处理
app.Run(async context =>
{
await context.Response.WriteAsync("未匹配处理!\r\n", Encoding.UTF8);
});
app.Run();
}
}
最后执行的路径和最开始的图是一致的。

为什么将context.Response.ContentType = "text/plain; charset=utf-8"; 放到第一个 Use 呢,因为如果放到 Run 里面会报错,改变了 Header 标头。所以理论上也不要在 Use 里面发送响应WriteAsync,此处为了演示所以这么写。

六、中间件类
上面的代理方法可以移动到类中,这个类就是中间件类。中间件类需要如下要求:
- 具有类型为 RequestDelegate 的参数的公共构造函数。
- 名为 Invoke 或 InvokeAsync 的公共方法。 此方法必须:
返回 Task。
接受类型 HttpContext 的第一个参数。
构造函数和 Invoke/InvokeAsync 的其他参数由依赖关系注入 (DI) 填充。
将上面的未匹配路由处理逻辑移动到中间件类中:
- TestMiddleware1:
public class TestMiddleware1
{
private readonly RequestDelegate _next;
public TestMiddleware1(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("第 1 个Use 开始!\r\n", Encoding.UTF8);
await _next(context);
await context.Response.WriteAsync("第 1 个Use 结束!\r\n", Encoding.UTF8);
}
}
- TestMiddleware2
public class TestMiddleware2
{
private readonly RequestDelegate _next;
public TestMiddleware2(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync("第 2 个Use 开始!\r\n", Encoding.UTF8);
await _next(context);
await context.Response.WriteAsync("第 2 个Use 结束!\r\n", Encoding.UTF8);
}
}
Program

运行

此处的中间件使用有顺序问题,如果我先app.UseMiddleware<TestMiddleware2>() 因为 TestMiddleware1 修改了标头,根据约定是不允许的,所以程序是有报错。

因此中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此顺序对于安全性、性能和功能至关重要。
七、中间件顺序

以上是内置中间件的默认顺序规则,具体如何使用内置中间件,可参阅官方资料。
八、写在最后
以上就是关于中间件的部分知识,结合我自己的理解做了前后衔接的梳理逻辑。
官方网站更多的是讲解每个知识点的细节,前后需要结合起来理解,当然我还是强烈建议跟着官方文档学习,而且是最权威最可信的:ASP.NET Core 中间件
这个系列历时1年多,工作生活都比较忙,也有放纵啥事不相干的时候,中间断断续续的,总算是坚持完了。很多东西就是这样,累了就休息一下贵在坚持,即使再慢,积累的成果也有收获。
.net 温故知新【17】:Asp.Net Core WebAPI 中间件的更多相关文章
- Asp.Net Core WebApi学习笔记(四)-- Middleware
Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...
- Asp.net Core WebApi 使用Swagger做帮助文档,并且自定义Swagger的UI
WebApi写好之后,在线帮助文档以及能够在线调试的工具是专业化的表现,而Swagger毫无疑问是做Docs的最佳工具,自动生成每个Controller的接口说明,自动将参数解析成json,并且能够在 ...
- ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- Asp.Net Core WebApi中接入Swagger组件(初级)
开发WebApi时通常需要为调用我们Api的客户端提供说明文档.Swagger便是为此而存在的,能够提供在线调用.调试的功能和API文档界面. 环境介绍:Asp.Net Core WebApi + S ...
- Asp.Net Core WebApi (Swagger+EF Core/Code First)
Swagger简介: Swagger™的目标是为REST APIs 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到文档或者不能通过网络流量检测的情况下能发现和理解各种服务的功能. ...
- ASP.NET Core WebAPI中的分析工具MiniProfiler
介绍 作为一个开发人员,你知道如何分析自己开发的Api性能么? 在Visual Studio和Azure中, 我们可以使用Application Insight来监控项目.除此之外我们还可以使用一个免 ...
- ASP.NET Core WebApi使用Swagger生成api
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- ASP.NET Core WebApi使用Swagger生成api说明文档
1. Swagger是什么? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件 ...
- Asp.net core WebApi 使用Swagger生成帮助页实例
最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效 ...
- 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...
随机推荐
- EF Core预编译模型Compiled Model
前言 最近还在和 npgsql 与 EF Core 斗争,由于 EF Core 暂时还不支持 AOT,因此在 AOT 应用程序中使用 EF Core 时,会提示问题: 听这个意思,似乎使用 Compi ...
- React 应用构建(环境)
可以少去理解一些不必要的概念,而多去思考为什么会有这样的东西,它解决了什么问题,或者它的运行机制是什么? 一. 环境搭建 工作编辑器:Visual Studio Code. Javascript 解析 ...
- JavaWeb项目练习(学生选课管理系统)二【新建数据库】
思路 1.页面美化css这部分,挖个坑,我打算做好一点所以先空着.× 2.需要做四个数据表(学生.教师.管理员.课程) 关联: 学生有个人课表 教师有教授课程和个人课表 管理员有全部权限(关联所有数据 ...
- Maven的安装与配置本地仓库,镜像源,环境变量。
参考视频: 黑马程序员2023新版JavaWeb开发教程,实现javaweb企业开发全流程 [小飞非系列]最新Maven实战教程-项目实战构建利器 一.下载Maven安装包 注意安装maven前要先安 ...
- 【已解决】【Tensorflow2.12.0版本以后合并CPU和GPU版】Tensorflow-gpu==2.12.0 安装失败解决办法
直接上解决方式,需要知道原因的看后文. 直接安装 tensroflow,从 2022 年 12 月起 tensorflow-gpu 已经合并到 tensorflow 包中了 pip install t ...
- Pattern类和Matcher类的使用
1.先看好数据源 先将一个String对象确定为程序要对其进行操作的数据源. String b="hello,good morning"; 2.建立Pattern类的对象 Stri ...
- Chrome扩展的核心:manifest 文件(上)
大家好,我是dom哥.我正在写关于 Chrome 扩展开发的系列文章,感兴趣的可以点个小星星. Chrome 在全球浏览器市场份额独占 6 成,无论是对普通用户还是开发者,都是电脑里的必备利器.Chr ...
- Head First Java学习:第十四章-序列化和文件
第十四章 序列化和文件的输入输出 保存对象 1.什么是序列化和反序列化 在编程的世界当中,常常有这样的需求:我们需要将本地已经实例化的某个对象,通过网络传递到其他机器当中,为了满足这种需求,就有了所谓 ...
- LeetCode5716:好因子的最大数目(数学、快速幂)
解题思路:因为primeFactors比较大,所以需要使用快速幂. class Solution: def quick_pow(self,base,x): ans = 1 while x>0: ...
- 华企盾DSC苹果Mac针对Word编辑文件不加密
解决方法:查看了客户端的控制台日志显示的进程名和加密后缀都正常,可能文件内部有rename的操作,加密所有类型解决