【ASP.NET Core】给中间件传参数的方法
最近博客更新频率慢了些,原因有三:
其一,最近老周每星期六都录 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】给中间件传参数的方法的更多相关文章
- 如何传递参数给ASP.NET Core的中间件(Middleware)
问题描述 当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗? 解决方案 在ASP.NET Core项目中添加一个POCO类来传递参数 ...
- asp.net core mvc 中间件之WebpackDevMiddleware
asp.net core mvc 中间件之WebpackDevMiddleware WebpackDevMiddleware中间件主要用于开发SPA应用,启用Webpack,增强网页开发体验.好吧,你 ...
- asp.net core mvc 中间件之路由
asp.net core mvc 中间件之路由 路由中间件 首先看路由中间件的源码 先用httpContext实例化一个路由上下文,然后把中间件接收到的路由添加到路由上下文的路由集合 然后把路由上下文 ...
- ASP.NET Core:中间件
一.什么是中间件 我们都知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终才会到达我们写的代码中.而中间件就是用于组成应用程序管道来处理请求和响应的 ...
- 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?
原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...
- 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的返回值自动进行各种序列化处理(序列化为 ...
- asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密。
原文:asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密. GitHub demo https://github.com/zhanglilong23/Asp.NetCore. ...
- ASP.NET Core路由中间件[3]: 终结点(Endpoint)
到目前为止,ASP.NET Core提供了两种不同的路由解决方案.传统的路由系统以IRouter对象为核心,我们姑且将其称为IRouter路由.本章介绍的是最早发布于ASP.NET Core 2.2中 ...
- ASP.NET Core路由中间件[2]: 路由模式
一个Web应用本质上体现为一组终结点的集合.终结点则体现为一个暴露在网络中可供外界采用HTTP协议调用的服务,路由的作用就是建立一个请求URL模式与对应终结点之间的映射关系.借助这个映射关系,客户端可 ...
随机推荐
- Linux进程管理:后台启动进程和任务管理命令
一.为什么要使程序在后台执行 我们的应用有时候要运行时间很长,如:几个小时甚至几个星期,我们可以让程序在后台一直跑. 让程序在后台运行的好处有: 终端关机不影响后台进程的运行.(不会终端一关机或者网络 ...
- 阿里云API网关(3)快速入门(调用 API)
网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...
- zuul入门(3)开发zuul的过滤器
1.编写Zuul过滤器(Java&Groovy) 理解过滤器类型和请求生命周期后,我们来编写一个Zuul过滤器.编写Zuul的过滤器非常简单,我们只需继承抽象类ZuulFilter,然后实现几 ...
- uva 1411 Ants
题意: 一个平面上有n个黑色的点,n个白色的点,要求黑色的点与白色点之间一一配对,且线段之间不相交. 思路: 线段不相交并不好处理,想了很久想不出,所以看了蓝书的讲解. 一个很明显的结论是,不相交的线 ...
- Django通过pycharm创建后,如何登录admin后台?
问题背景: 使用pycharm创建完成django项目(项目名称为:mydjangopro,app名称为my_blog) , 本想登录后台直接输入地址:http://127.0.0.1:8000/ad ...
- php实现记住密码自动登录的功能
$username=trim($_POST['username']); $password=md5(trim($_POST['password'])); $ref_url=$_GET['req_url ...
- MySQL导致错误的语句
主键不唯一 由于表定义中创建了主键约束,因此MySQL将会确保重复主键不会被插入到数据表中. INSERT INTO person (person_id, fname, lname, gender, ...
- VC2013 代码图,依赖项关系图,等出错解决办法.
环境WIN10+VS2013+SQL2015 当VS2013代码图,依赖项关系图等出现 数据库连接错误时 去http://www.microsoft.com/zh-cn/download/detail ...
- [LeetCode] Student Attendance Record II 学生出勤记录之二
Given a positive integer n, return the number of all possible attendance records with length n, whic ...
- IOS开发- 访问通讯录,并将通讯录中姓名-头像-手机号码 发给服务器
现在很多软件都会访问通讯录,并将通讯录的信息取得,发给服务器,然后服务器会返回相应电话号码的用户是否注册. 现在分享一下前两步,访问通讯录并处理通讯录的信息 1.导入框架 #import <Ad ...