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

其一,最近老周每星期六都录 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. api-gateway实践(15)API网关的待改进点 20171207

    一.API网关能力 API网关负责服务请求路由.组合及协议转换.客户端的所有请求都首先经过API网关,然后由它将请求路由到合适的微服务.API网关的客户端通过统一的网关接入微服务,在网关层处理所有的非 ...

  2. istio入门(01)istio的优势在哪里?

    Istio能做什么?Istio 试图解决微服务实施后面临的问题.Istio 提供了一个完整的解决方案,对整个服务网格行为洞察和操作控制,以满足微服务应用程序的多样化需求. Istio在服务网络中提供了 ...

  3. api-gateway实践(02)新服务网关 - 运行环境

    一.服务网关的运行环境 1.服务配置中心 1.1.服务配置中心前台 前台 http://10.110.17.20/#/login:无源码,德奎部署在10.110.17.20的DockerStatck环 ...

  4. 使用SQL语句在SQL server2017上创建数据库

    软件基础:在电脑上提前安装好SQL server2017,并且安装好其中的SSMS(SQL server Management Studio) 创建方式:SQL语句 操作内容:创建零件供应数据库系统 ...

  5. pandas(七)数据规整化:清理、转换、合并、重塑之合并数据集

    pandas对象中的数据可以通过一些内置的方式进行合并: pandas.merge 可根据一个或多个键将不同的DataFrame中的行连接起来. pandas.concat可以沿着一条轴将多个对象堆叠 ...

  6. .Net中Web增加加密狗管理

    由于业务中最近需要使用到加密狗,增加对Web代码的管控,所以需要进行加密狗使用的研究 首先,对于没有接触使用过加密狗的人需要有个大致的认识,加密狗分为 MasterDog, 1.下载加密狗的开发套件, ...

  7. maven中scope标签以及exclusions 记录

    scope的分类 1.compile:默认值 他表示被依赖项目需要参与当前项目的编译,还有后续的测试,运行周期也参与其中,是一个比较强的依赖.打包的时候通常需要包含进去 2.test:依赖项目仅仅参与 ...

  8. java中的内部类概念

    内部类和外部类可以互相访问私有属性 1.普通内部类实例化方式 外部类.内部类 对象 = new 外部类().new 内部类(); class Outer{//外部类 private String ms ...

  9. 0308-标签的用法(a,ul/ol,table)

    标签分为: 一般标签:<div> <span> <br/> <hr/> 功能标签:<a> <img> 实体标签:≶ > s ...

  10. window10下安装linux虚拟机

    一.准备工具 虚拟机.镜像.putty 1.安装虚拟机 VMware Workstation Pro 安装成功之后需要输入密钥,请点击以下链接 http://www.360doc.com/conten ...