前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Asp.NetCore Web开发之请求管道和中间件(二)

Asp.NetCore Web开发之请求管道和中间件(二)

作者头像
宿春磊Charles
发布2022-03-29 09:30:36
3760
发布2022-03-29 09:30:36
举报
文章被收录于专栏:DotNet 致知

这节演示一下自定义中间件,第一节我们讲到,中间件的处理流程就像一个俄罗斯套娃,那这种俄罗斯套娃型的流程内部是如何实现的呢,下面请看代码。

第一种写法是直接写在Configure方法中的,使用app.Use(委托)配合lambda表达式使用,适合很轻量级的中间件。

代码语言:javascript
复制
 app.Use(async (context, next) =>
  {
      await context.Response.WriteAsync("CustomerMiddleWare1-in\n");
      await next();
      await context.Response.WriteAsync("CustomerMiddleWare1-out");
  });

微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件(这就是套娃模式的由来)。

这也限制了方法,必须是异步的async方法,调用next()之后,上下文对象发送给下一中间件了,该方法就会处于等待状态,直到后续的中间件处理完毕,返回后,执行next()方法之后的代码。(关于同步和异步的有关知识,将在后续进行讲解)

除了使用Use()方法,还有一种用法,这个方法有点特殊,因为它不存在next()方法传递上下文对象,它是请求管道的底,用于直接返回响应

代码语言:javascript
复制
 //run 是终端中间件,他是没有next()方法的,只要进入这个中间件,后续的中间件都不会执行了,从它这里请求完毕原路返回 
app.Run(async context =>
{
    await context.Response.WriteAsync("I am End MiddleWare\n");
});

也就是说,通过这个Run()中间件,我们才会真正形成套娃模式,如果都是用Use()一直传递到最后一个中间件, 它就不存在后续中间件去接收next(),所以,一般都是Use()....Run(),这样的中间件流程。

.ASP NetCore 3.x推出了一个新的中间件,叫EndPoints

代码语言:javascript
复制
 app.UseEndpoints(endpoints =>
  {
      endpoints.MapControllerRoute(
          name: "default",
          pattern: "{controller=Home}/{action=Index}/{id?}");
  });

它跟Run()一样,是兜底的中间件,但是用法比较特殊了,微软给我们的默认配置就是直接路由到某一页面,一般是网站首页。

下面看一下运行结果的演示,有如下三个中间件:

代码语言:javascript
复制
 //use是添加中间中间件,就是处理完了,继续传给下一个中间件,它有next()委托
  app.Use(async (context, next) =>
  {
      await context.Response.WriteAsync("CustomerMiddleWare1-in\n");
      await next();
      await context.Response.WriteAsync("CustomerMiddleWare1-out");
  });
  app.Use(async (context, next) =>
  {
      await context.Response.WriteAsync("CustomerMiddleWare2-in\n");
      await next();
      await context.Response.WriteAsync("CustomerMiddleWare2-out\n");
  });
  //run 是终端中间件,他是没有next()方法的,只要进入这个中间件,后续的中间件都不会执行了,从它这里请求完毕原路返回 
  app.Run(async context =>
  {
      await context.Response.WriteAsync("I am End MiddleWare\n");
  });

运行结果为:

这很直观的反应了中间件的顺序执行,以及嵌套执行,也直观的看出了套娃模式,你也可以把他想象成一个开口向上的抛物线,一端是请求,一端是响应。

下面看一下如何定义一个真正的自定义中间件

首先,我们要明确,微软规定的自定义中间件的要求

1.具有类型为RequestDelegate参数的公共构造函数,这个参数就是请求委托,它在一个个的中间件中传递

2.具有Invoke或者InvokeAsync的方法,该方法的返回值必须是Task,而且第一个参数必须是HttpContext

代码语言:javascript
复制
 public class MyMiddleWare
 {
        private readonly RequestDelegate _next;
        public MyMiddleWare( RequestDelegate next )
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            //此处写中间件业务逻辑
            //然后调用next指向下一个中间件
            //调用next之前,属于请求部分的处理
            await _next(context);
            //next执行完毕之后,属于相应部分的处理
        }
    }

定义完成以后,使用UseMiddleware<中间件>()将自定义中间件添加进来(这种用法属于泛型的知识)

代码语言:javascript
复制
app.UseMiddleware<MyMiddleWare>();

但这样的用法,还是少了一点优雅与灵活性,我们可以通过扩展方法的形式,为IApplicationBuilder添加扩展方法,实现自定义中间件添加与配置的灵活应用(扩展方法在之前的文章中有讲)

代码语言:javascript
复制
public static class MyMiddleWareExtension
{
    public static IApplicationBuilder UseMymiddleware(this IApplicationBuilder app)
    {
        return app.UseMiddleware<MyMiddleWare>();
    }
}

这样的话,就可以直接调用方法添加中间件了

代码语言:javascript
复制
 //使用扩展方法的形式,添加自定义中间件然后可以通过构造方法的形式,传递配置参数
 app.UseMymiddleware();

初学者可对此做初步了解,但对其中涉及的代码语法知识(委托,lambda表达式,扩展方法,泛型),却是必须要掌握的。另外,如果需要查看ASP.NetCore的源码,请访问https://github.com/dotnet/aspnetcore自行下载或克隆到本地

本节到此结束...

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet 致知 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档