zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

《ASP.NET Core技术内幕与项目实战》精简集-WebApi3.2:中间件Middleware

2023-03-20 15:33:41 时间

本节内容,涉及到7.6(P229-P242),以WebApi说明为主。主要NuGet包:无

 

一、图解中间件

 

1、服务器收到HTTP请求后,需要对请求进行一系列处理;当控制器中的操作方法完成后,也会对响应进行一系列处理。这一系列操作,如果全部硬编码到AspNetCore框架中,代码耦合度会很高。所以框架只完成HTTP请求响应调度和报文解析,其他可选工作由不同的中间件来完成。

2、在一个中间件中,有三部分组织,①前逻辑;②next方法;③后逻辑。HTTP请求到达服务器后,先由框架进行请求解析,然后进入第一个中间件,先执行前逻辑,然后由中间件自己决定是否执行next.Invoke(),如不执行,则请求中断,如执行,则请求进入下一个中间件。WebApi控制器的方法执行后,响应倒序从最后一个中间件开始,执行中间件的后逻辑。

3、每一次HTTP请求,框架会自动生成一个HttpContext类型的对象,称之为上下文,可以记录了请求路径、请求参数、请求客户端、响应报文、响应流、用户、自定义Items等信息。在中间件的前后逻辑和控制器中,均可以对HttpContext对象进行读写操作。

 

 

二、图解管道(pipeline)

 1、上图中,每一个Use代表一个中间件,最后在Run中执行完请求,然后将响应返回。Use和Run组成一个HTTP请求的处理管道,而Map决定每个管道用于处理什么请求,Map("/test1")表示请求路径。如图所示,当服务器收到一个请求路径为"/test1"的HTTP请求时,就按管道1来处理。

2、我们用VS创建一个默认的WebApi项目时,在项目入口(Program.cs的Main方法)中,有很多“app.Use...”开头的代码,以及一个"app.Run()",这些不在Map定义的管道中的中间件,会默认处理所有请求。实际项目中,我们并不需要定义自己的Map管道,项目入口处定义的中间件,处理所有请求。也可以认为,AspNetCore默认为我们定义了一个处理所有请求的管道。

3、以下代码定义了一个处理“/test”请求的特殊管理 

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//指定处理“/test”路径请求的管道
app.Map("/test", async appBuilder =>
{
    //第一个中间件
    appBuilder.Use(async (context, next) =>
    {
        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync("1 Start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("1 End<br/>");
    });
    //第二个中间件
    appBuilder.Use(async (context, next) =>
    {
        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync("2 Start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("2 End<br/>");
    });
    //Run终点
    appBuilder.Run(async ctx =>
    {
        await ctx.Response.WriteAsync("hello,it is run<br/>");
    });
});

app.Run();

 

 

 三、AspNetCore的常见中间件

 

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    //开发环境中,捕捉异常
    app.UseDeveloperExceptionPage();
    //OpenApi+Swagger中间件
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseExceptionHandler("/Error"); //生产环境中,捕捉异常

app.UseCors(); //跨域中间件,设置响应报文头允许跨域

app.UseHttpsRedirection(); //HTTP请求重定向到HTTPS

app.UseCookiePolicy(); //Cookie策略中间件

app.UseSession(); //会话中间件,建立和维护会话状态

app.UseAuthentication(); //认证,哪些用户可以登陆访问

app.UseAuthorization(); //授权,登陆用户可以访问哪些资源

app.UseFileServer(); //默认文件、静态文件、目录浏览

app.MapControllers(); //控制器,包括路由

app.Run();

 

 

 

四、自定义一个简单的中间件

 1 //定义一个中间类
 2 //CheckMiddleware.cs
 3 public class CheckMiddleware
 4 {
 5     private readonly RequestDelegate next;
 6     public CheckMiddleware(RequestDelegate next)
 7     {
 8         this.next = next;
 9     }
10 
11     public async Task InvokeAsync(HttpContext context)
12     {
13         string pwd = context.Request.Query["password"];
14         if (pwd == "123")
15         {
16             await next(context);
17         }
18         else
19         {
20             context.Response.StatusCode = 401;
21         }
22     }
23 }
24 
25 
26 //使用中间件
27 //Program.cs
28 var builder = WebApplication.CreateBuilder(args);
29 ......
30 var app = builder.Build();
31 ......
32 app.Map("/test", async appBuilder =>
33 {
34     appBuilder.UseMiddleware<CheckMiddleware>();
35     appBuilder.Run(async context =>
36     {
37         context.Response.ContentType = "text/html";
38         context.Response.StatusCode = 200;
39         await context.Response.WriteAsync("<h1>success!</h1>");
40     });
41 });
42 app.Run();

代码解读:

3-23行:中间件类是一个普通的类,没有继承和实现。但有几个固定成员:①注入RequestDelete对象;②返回值为Task的方法InvokeAsync,且参数为HttpContext

5-9行:注入RequestDelete对象,这个对象用来指向下一个中间件,如果不调用,则请求中止。调用前为中间件的前逻辑,调用后为后逻辑。

13-17行:从HttpContext对象里,读取请求的query参数password,如果密码为123,则执行下一个中间件,否则就报401错误

32-41行:当请求路径为"/test"时,执行自定义的管道,这个管道中有一个中间件CheckMiddleware,还有一个Run的处理逻辑

 补充说明:

①除了Map方法之外,还有MapGet、MapPost、MapWhen等指定管道的方法,但实际项目中,如果不是开发框架,比较少用到Map

②大部分时间,我们极少需要自己定义中间件,一般都使用框架定义好的中间件,所以对框架提供的中间件要熟悉,另外要熟悉HttpContext对象的常用成员

③书中还有两个很精彩的案例:自己动手模仿WebApi框架、Markdown转换器中间件

 

 

特别说明:
1、本系列内容主要基于杨中科老师的书籍《ASP.NET Core技术内幕与项目实战》及配套的B站视频视频教程,同时会增加极少部分的小知识点
2、本系列教程主要目的是提炼知识点,追求快准狠,以求快速复习,如果说书籍学习的效率是视频的2倍,那么“简读系列”应该做到再快3-5倍