最近博客更新频率慢了些,原因有三:

其一,最近老周每星期六都录 ASP.NET Core 的直播,有些内容在视频里讲过,就不太想在博客里面重复。有兴趣的话可以去老周的微博看,或者去一直播,直播帐号与微博帐号是绑定的;

其二,最近老周是有些忙,但不是忙写代码的事情。而是忙着“寻宝藏”。

其三,每个星期至少也要抽出一天的时间,跟妹子出去浪。准确地说,应该叫对象(Object),是通过构造函数认识的,已经顺利运行有五个月了。目前状态良好,内存占用小,不烧 CPU。性能好,不吃硬件。

好了,屁话不多说了。今天说说如何向中间件传参数的事。

首先,用宇宙中最通俗的语言介绍一下啥是中间件。浏览器或客户端向服务器发出请求后,HTTP 请求会进入通信管道,然后由一个个中间件来进行处理,A 处理完了,交给 B;B 处理完了再交给 C……所有中间件就串成一条链,直到最后一个中间件(HTTP 404)。处理完后就把结果返回给调用者。

所以说,中间件就是一个处理 HTTP 请求的“零件”,比如,你可以定义一个中间件,对请求中的某些数据进行解密或者验证。或者,你可以定义一个中间件来添加自己定义的 HTTP 头。

中间件在代码中由一个 RequestDelegate 委托来表示,该委托声明如下。

delegate System.Threading.Tasks.Task RequestDelegate(Microsoft.AspNetCore.Http.HttpContext context)

HttpContext 可以保持整个 HTTP 请求上下文中的数据与状态,并且在调用每一个中间件时,会将自身传递过去。返回类型为 Task,表示支持异步等待。

对于代码简单的中间件,可以直接 Use 扩展方法,比如这样。

            app.Use(async (context, next) =>
{
context.Response.Headers.Add("key", "no key");
await next();
});

next 是指处理链条上的下一个中间件,如果没特殊事情,在当前代码处理完后应该调用下一个中间件。当然,如果没有必要调用下一个中间件,那可以不调用 next,这样,整个 HTTP 通信管道就中止了。

但是,如果中间件逻辑多,代码多,而且又要接收参数的话,那就应该用一个类来封装。封装的时候一定要注意相关的约定。

中间件必须包含一个 Invoke 或 InvokeAsync 方法,方法的参数为 HttpContext,返回类型为 Task。

为什么要这个约定呢?你看看刚刚那个 RequestDelegate 委托。委托类型的实例是不是有个 Invoke 方法?这就对了,大概为了方便记忆,所以代码约定也使用了 Invoke 这名字。在运行的时候,框架会在中间件类中寻找名字为 Invoke 或 InvokeAsync 的方法。所以,要想自定义的中间件类起作用,你应该遵守这个约定。

我们今天讨论的重点是向中间件传参数,要能传参的话,就必须写一个中间件类。先说说,怎么传参。方法有二。

一、IApplicationBuilder 的 UseMiddleware 扩展方法,此方法的参数列表中,最后一个是加了 params 关键字的 object 数组。这个就是用来传参数的,而且参数的个数是不确定的。传入的参数从中间件类的构造函数中接收。

二、通过依赖注入自动获取。虽然中间件类的构造函数可以接收注入对象,但是,不推荐在这里接收注入对象,因为这样会改变注入对象的生命周期。由于中间件类在运行阶段只实例化一次,故它的生命周期应与应用程序相等。所以,如果通过构造函数获取注入的话,由于注入对象长期存在引用,使得服务容器无法释放它。如果注入对象是用 AddTransient 方法添加到服务集合中,本应该每次使用后释放,但由于实例被引用,就会导致生命周期变得与应用程序同等,所以,不应该在中间件类的构造函数中来注入,而应该在 Invoke 或 InvokeAsync 方法中进行注入。

来来来,动手,咱们用实例来学习,效果会番十倍的。

先写一个中间件类。

    public class DemoMiddleware
{
RequestDelegate _next;
double mx, my; public DemoMiddleware(RequestDelegate next, double x, double y)
{
_next = next;
mx = x;
my = y;
} public async Task InvokeAsync(HttpContext context)
{
double r = mx + my;
context.Response.Headers["Compute-Result"] = $"{mx} + {my} = {r}";
await _next(context);
}
}

注意啊各位,中间件类的构造函数,一般都要一个 RequestDelegate 的参数,干吗用的呢?就是让你可以调用下一个中间件,它代表的是链条上的下一个中间件。

两个 double 类型的参数才是我们真正要传的参数。在 InvokeAsync 方法中,我做了一个简单处理,把两个参数的值相加,然后通过 HTTP 头返回给客户端。

为了使下一个中间件能被调用,记得在 InvokeAsync 方法的最后调用一下 _next 字段。

现在,回到 Startup 类,找到 Configure 方法,我们使用刚刚定义的中间件类。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
…… app.UseMiddleware<DemoMiddleware>(15.33d, 8.96d);
}

参数就是通过 UseMiddleware 方法来传递给中间件类的,有几个就传几个,该什么类型就什么类型,因为参数签名是 object 类型,有容乃大,它能兼容所有类型。

现在我们来测试一下。运行之后,你发现浏览器得到的是 404,对的,前面老周说了,中间件链条的最后一个中间件就是 404。我们没有向客户端回写任何内容,所以返回 404 太正常了。但是,代码其实是成功执行了的。

你可以打开抓包工具(比如 F12 工具里面就有),然后刷新一下,随后你去看一下返回消息的 Http 头。

看到了吧,说明中间件是执行了的。

下面,我们用依赖注入,在中间件中获取参数。

    public class Demo2Middleware
{
RequestDelegate _next; public Demo2Middleware(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext context, IHostingEnvironment env)
{
context.Response.Headers["app-name"] = env.ApplicationName;
context.Response.Headers["env-name"] = env.EnvironmentName;
await _next(context);
}
}

在 Invoke 方法中,第一个参数是 HttpContext,这个东东是必须的,然后后面我们获取一个 IHostingEnvironment,这个在应用程序初始化时由框架自动添加到服务容器中,它会自动注入到 Invoke 方法中。在上面代码中,我只是把应用名称和运行环境名称添加到 HTTP 头中。

随后在 Startup 类的 Configure 方法中,也用上这个中间件。

       app.UseMiddleware<Demo2Middleware>();

运行之后,刷新浏览器,再抓包,你就看到在 Http Header 集合中多了几个东东。

爽吧,中间件也顺利执行了。

其实,你仔细一看就会发现,这个 Invoke / InvokeAsync 方法的注入方式与 Startup 类的 Configure 方法是一样的。Configure 方法的第一个参数是必须的,型类为 IApplicationBuilder,后面的参数就是注入的。

好了,向中间件传参数的两种方法都介绍完了。

最后,顺便说一下,“五一”假期前老周可能会直播一次 ASP.NET Core ,但不保证会开播,如果这几天没弄的话,就要等“五一”假期之后再开播。

【ASP.NET Core】给中间件传参数的方法的更多相关文章

  1. 如何传递参数给ASP.NET Core的中间件(Middleware)

    问题描述 当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗? 解决方案 在ASP.NET Core项目中添加一个POCO类来传递参数 ...

  2. asp.net core mvc 中间件之WebpackDevMiddleware

    asp.net core mvc 中间件之WebpackDevMiddleware WebpackDevMiddleware中间件主要用于开发SPA应用,启用Webpack,增强网页开发体验.好吧,你 ...

  3. asp.net core mvc 中间件之路由

    asp.net core mvc 中间件之路由 路由中间件 首先看路由中间件的源码 先用httpContext实例化一个路由上下文,然后把中间件接收到的路由添加到路由上下文的路由集合 然后把路由上下文 ...

  4. ASP.NET Core:中间件

    一.什么是中间件 我们都知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终才会到达我们写的代码中.而中间件就是用于组成应用程序管道来处理请求和响应的 ...

  5. 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?

    原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...

  6. ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目

    ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)   我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为 ...

  7. asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密。

    原文:asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密. GitHub demo https://github.com/zhanglilong23/Asp.NetCore. ...

  8. ASP.NET Core路由中间件[3]: 终结点(Endpoint)

    到目前为止,ASP.NET Core提供了两种不同的路由解决方案.传统的路由系统以IRouter对象为核心,我们姑且将其称为IRouter路由.本章介绍的是最早发布于ASP.NET Core 2.2中 ...

  9. ASP.NET Core路由中间件[2]: 路由模式

    一个Web应用本质上体现为一组终结点的集合.终结点则体现为一个暴露在网络中可供外界采用HTTP协议调用的服务,路由的作用就是建立一个请求URL模式与对应终结点之间的映射关系.借助这个映射关系,客户端可 ...

随机推荐

  1. SpringCloud的应用发布(四)vmvare+linux,防火墙和selinux

    一.vmvare网络配置为nat模式 二.vmvare的网络设置为桥接bridge模式 1.linux 网卡的ip获取方式dhcp 三.关闭linux的防火墙和selinux 1.临时关闭防火墙 sy ...

  2. SpringBoot入门:新一代Java模板引擎Thymeleaf(理论)

    Spring Boot 提供了spring-boot-starter-web来为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及SpringMVC的 ...

  3. 老男孩python学习之作业一购物小程序

    想学编程由来已久 始终没有个结果,痛心不已 如今再次捡起来,望不负期望,不负岁月 ......一万字的废话...... 先介绍一下我的自学课程吧 "路飞学城"的<python ...

  4. uvalive 3213 Ancient Cipher

    https://vjudge.net/problem/UVALive-3213 题意: 输入两个字符串,问是否可以由第一个字符串的每个字符一一映射得到第二个字符串,字符是可以随意移动的. 思路: 统计 ...

  5. Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) C. Classroom Watch

    http://codeforces.com/contest/876/problem/C 题意: 现在有一个数n,它是由一个数x加上x每一位的数字得到的,现在给出n,要求找出符合条件的每一个x. 思路: ...

  6. js实现继承的5种方式

    js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式1.使用对象冒充实现继承(该种实现 ...

  7. 最短路径之Dijkstra算法

    Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最短路径的最优 ...

  8. SpringBoot: 配置加载顺序

    在应用程序中各种配置是不可避免的,Spring中对配置的抽象(Environment)可以说是达到了极致,其中有一项尤为突出:PropertySource(配置来源),配置来源通常包括命令行参数,系统 ...

  9. laypage分页控件使用方法

    laypage是一款非常简单易用的分页控件,由于最近项目中使用到了,简单记录一下使用方法 1.引入laypage所需的js和css文件 <link href="js/laypage/1 ...

  10. .NET MD5 加密

    using System; using System.Security.Cryptography; using System.Text; namespace Md5Demo { /// <sum ...