知行合一|

hiwwwk

园龄:5年1个月粉丝:4关注:12

2022-02-09 00:02阅读: 66评论: 0推荐: 0

21 | 中间件:掌控请求处理过程的关键

中间件的工作原理


ASP.NET Core 请求管道包含一系列请求委托,依次调用。

每个委托均可在下一个委托前后执行操作。 应尽早在管道中调用异常处理委托,这样它们就能捕获在管道的后期阶段发生的异常。

核心对象

  • IApplicationBuilder
  • RequestDelegate
    • RequestDelegate就是我们处理整个请求的委托


看一下**IApplicationBuilder****RequestDelegate**的定义

namespace Microsoft.AspNetCore.Builder
{
     //定义提供配置应用程序请求的机制的类管道。
    public interface IApplicationBuilder
    {
        IServiceProvider ApplicationServices { get; set; }
        IDictionary<string, object> Properties { get; }
        IFeatureCollection ServerFeatures { get; }
        RequestDelegate Build();
        IApplicationBuilder New();
        // IApplicationBuilder可以让我们去注册我们的中间件
        IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
    }
}

IApplicationBuilderUse可以让我们去注册我们的中间件,每一个委托的入参也是一个委托


RequestDelegate这个委托的入参就是一个HttpContext

namespace Microsoft.AspNetCore.Http
{
    public delegate Task RequestDelegate(HttpContext context);
}

所有注册中间件的委托实际上都是对HttpContext的处理。


之前我们记录到过lStartup类,Configure方法是用来注册我们的中间件的。
根据上面流程图,发现中间件的执行顺序是跟我们的注册顺序是有关系的
最早注册的中间件它的权力最大,可以越早发生作用。


我们不仅仅可以使用内置的中间件,也可以使用注册委托的方式来注册我们的逻辑。


新建Web程序👉选择API模板👉Startup类,Configure方法

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.Use(async (context, next) =>
	{
        // 不对next进行任何操作
		await context.Response.WriteAsync("Hello World!");
	});

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
	{
		endpoints.MapControllers();
	});
}

我们不对next进行任何操作
执行程序:image.png
可以发现,页面只输出了Hello World!如果需要后续的中间件操作,那么要在最后执行**next**委托

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

执行输出:image.png
发现页面是一片空白,这是因为,我们response已经启动。一旦我们的应用程序已经对**response**输出内容,我们就不能对**header**进行操作了,但是可以在response后续继续写出信息
我们将context.Response.WriteAsync("Hello World!")移动到next后面

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

执行输出:image.png     可以发现,在Json后面添加了我们输出的HelloWorld
如果我们对response输出内容,还继续对header进行操作的话就会触发异常。可以通过 Context.Response.HasStarted来判断是否进行过操作。




除了Use这种方式之外,还有Map方式。
Map这个函数,它的作用是我们对特殊的路径,比如hi进行处理

app.Map("/hi", hiBuilder => 
{
	hiBuilder.Use(async (context, next) =>
	{
        await next();
        await context.Response.WriteAsync("Hello World!");
    });
});

启动之后,将路径修改为hiimage.png




如果我们在Map的时候,逻辑复杂一点,不仅仅是判断它的URL地址,而且还要做特殊的判断的话,可以使用MapWhen
比如说,我们请求的地址中条件包含hi的时候
方法参数:image.png

app.MapWhen(context => context.Request.Query.Keys.Contains("hi"), builder =>
{
    builder.Run(async context => await context.Response.WriteAsync("hi!"));
});

执行输出:image.png
这里我们用到了不同的方法Run
**Use**是指我们可以向注册一个完整的中间件一样,将我们的**next**也注入进来,我们可以去决定是否执行后续的中间件。
**Run**的含义就表示我们这里就是中间件执行的末端,也就不再执行后面的中间件了。




我们如何像UseRoutingUseEndpoints一样来设置我们自己的中间件呢
右键项目👉新建文件夹Middlewares👉新建类MyMiddlewareMyBuilderExtensions
定义中间件我们使用了一个约定的方式:我们的中间件的类包含了**Invoke**或者**InvokeAsync**这样一个方法,入参是**HttpContext**,返回是一个**Task**

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace LoggingSerilogDemo.Middlewares
{
    class MyMiddleware
    {
        private readonly ILogger<MyMiddleware> _logger;
        private readonly RequestDelegate _next;

        public MyMiddleware(ILogger<MyMiddleware> logger, RequestDelegate next)
        {
            _logger = logger;
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            _logger.LogInformation("Begin!");

            await _next(context);

            _logger.LogInformation("End!");
        }
    }
}

MyBuilderExtensions类定义扩展方法方便直接注册

using LoggingSerilogDemo.Middlewares;

namespace Microsoft.AspNetCore.Builder
{
    public static class MyBuilderExtensions
    {
        public static IApplicationBuilder AddMyMiddleware(this IApplicationBuilder app) 
        {
            return app.UseMiddleware<MyMiddleware>();
        }
    }
}

Configure方法里注册app.AddMyMiddleware()
执行程序:image.png

本文作者:hiwwwk

本文链接:https://www.cnblogs.com/wwwk/p/15873401.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hiwwwk  阅读(66)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起