中间件是一种装配到应用管道以处理请求和相应的软件.每个软件都可以:

1.选择是否将请求传递到管道中的下一个组件;

2.可在调用管道中的下一个组件前后执行工作.

管道由 IApplicationBuilder 创建:

每个委托都可以在下一个委托前后执行操作,.此外,委托还可以决定不将请求传递给下一个委托,这就是对请求管道进行短路.通常需要短路,是因为这样可以避免不必要的工作.比如:

1.静态文件中间件可以返回静态文件请求并使管道的其余部分短路;

2.现在管道中调用异常处理委托,以便他们可以捕获在管道的后期阶段所发生的异常.

委托的添加方式一共有3种:

1.Run

该方法的XML注释是这样写的:

Adds a terminal middleware delegate to the application's request pipeline.向应用程序请求管道添加一个终端中间件.

通俗来讲,意思就是该方法添加的委托,会使"请求管道短路",不管该委托是否提前响应都会短路.比如下面代码中标红的部分,不管有没有这一句代码,下面的所有代码都不会执行.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello World!");
}); //下面的都不会执行了,因为上面的委托已经终止了管道,或者说:"已经让管道短路了"
...
}

2.Use

该方法的XML注释是这样写的:

Adds a middleware delegate defined in-line to the application's request pipeline.和上面的 Run 方法相比,少了"terminal".意义就已经很明显了.

                //用 Use 将多个请求委托链接在一起. next 参数表示管道中的下一个委托,可通过不调用 next 参数使管道短路.
//通常可在下一个委托前后执行操作,如以下示例
app.Use(async (context, next) =>
{
var name = context.Request.Query["name"];
if (!string.IsNullOrWhiteSpace(name))
{
await context.Response.WriteAsync($"hello world , {name}");
}
await next.Invoke();
});

请求一:

请求二:

3.Map

根据给定请求路径的匹配项来创建请求分支.如果请求路径以给定的路径开头,则执行分支,如红色部分代码

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//Map
app.Map(new PathString("/map1"), MapTest1);
app.Map("/map2", MapTest2);
app.MapWhen(context => !string.IsNullOrWhiteSpace(context.Request.Query["name"]), MapTest3); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
} public void MapTest1(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("this is maptest1"); });
} public void MapTest2(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("this is maptest2"); });
} public void MapTest3(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("this is maptest3"); });
}

另外,Map 支持嵌套 :  app.Map("/map2", builder => { builder.Map("/map22", MapTest22); });

封装中间件

在实际运用过程中,我们通常将中间件封装在类中,然后通过扩展方法公开出来.方式有两种:

一.启动时构造

1.自定义中间件

    public class MyMiddleware
{
private readonly RequestDelegate _next; public MyMiddleware(RequestDelegate next)
{
_next = next;
} //方法名必须是 Invoke 或者 InvokeAsync
public async Task InvokeAsync(HttpContext context)
{
var name = context.Request.Query["name"];
if (!string.IsNullOrWhiteSpace(name))
{
await context.Response.WriteAsync($"hello world,{name}");
}
else
{
await _next(context);
}
}
}

2.通过扩展方法公开

    public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<MyMiddleware>();
}
}

3.调用自定义的中间件.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
} //调用自制中间件
app.UseMyMiddleware(); app.UseHttpsRedirection();
app.UseMvc();
}

这种方式编写的中间件,是在web应用启动时构造的,而不是按请求构造的,因此相当于单例.

所以,如果想正确使用中间件依赖项的生存期,则需要将这些依赖项添加到 Invoke 或者 InvokeAsync 方法的入参里面,如:

    public class Person
{
public string Name { get; set; }
}
    public class Startup
{
...other codes public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//services.AddSingleton(new Person() { Name = "admin" });
//services.AddTransient<Person>();
services.AddScoped<Person>();
}
...other codes
}
        //方法名必须是 Invoke 或者 InvokeAsync
public async Task InvokeAsync(HttpContext context, Person person)
{
var name = context.Request.Query["name"];
if (!string.IsNullOrWhiteSpace(name))
{
await context.Response.WriteAsync($"hello world,{name},the person`s hashcode is {person.GetHashCode()}");
}
else
{
await context.Response.WriteAsync($"hello world,{person.Name},the person`s hashcode is {person.GetHashCode()}");
}
}

二.按请求激活

该方式需要自定义中间件实现 IMiddleware 接口.

    public class MyMiddleware : IMiddleware
{
private readonly Person _person; public MyMiddleware(Person person)
{
_person = person;
} public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var name = context.Request.Query["name"];
if (!string.IsNullOrWhiteSpace(name))
{
await context.Response.WriteAsync($" {name} , hello ! the model`s hashcode is {this.GetHashCode()}");
}
else
{
await context.Response.WriteAsync($" {_person.Name} hello ! the model`s hashcode is {this.GetHashCode()}");
}
}
}

扩展方法的代码没变:

    public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<MyMiddleware>();
}
}

调用自制的中间件:

    public class Startup
{ public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//将中间件对象按我们需要的生存期注入到容器中.
//services.AddTransient<MyMiddleware>();
//services.AddScoped<MyMiddleware>();
services.AddSingleton<MyMiddleware>();        services.AddSingleton(new Person { Name = "admin" });
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//注册我们的中间件
app.UseMyMiddleware(); app.UseHttpsRedirection();
app.UseMvc();
}
}

...未完待续

ASP.NET Core 2.2 基础知识(二) 中间件的更多相关文章

  1. ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求

    可以注册 IHttpClientFactory 并将其用于配置和创建应用中的 HttpClient 实例. 这能带来以下好处: 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例. 例如 ...

  2. ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述

    为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ...

  3. ASP.NET Core 2.2 基础知识(十六) SignalR 概述

    我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节. 就好像这个图: 所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microso ...

  4. ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)

    要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ...

  5. ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务

    在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ...

  6. ASP.NET Core 2.2 基础知识(六) 配置(内含MySql+EF)

    先上一段代码,了解一下 .NET Core 配置数据的结构. 新建一个 控制台项目,添加一个文件 json.json ,文件内容如下: { "country": "cn& ...

  7. ASP.NET Core 2.2 基础知识(五) 环境

    一.环境变量 系统启动时,会读取环境变量 ASPNETCORE_ENVIRONMENT ,并将该变量的值存储在 IHostingEnvironment.EnvironmentName 字段中.如: 新 ...

  8. ASP.NET Core 2.2 基础知识(四) URL重写中间件

    说到URL重写就不得不提URL重定向. URL重定向 URL重定向是客户端操作,指示客户端访问另一个地址的资源.这需要往返服务器,并且当客户端对资源发出请求时,返回客户端的重定向URL会出现在浏览器的 ...

  9. ASP.NET Core 2.2 基础知识(十三) WebAPI 概述

    我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ...

随机推荐

  1. [NOI2010]能量采集 解题报告

    [NOI2010]能量采集 题目描述 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. ...

  2. BZOJ 3270 博物馆 && CodeForces 113D. Museum 期望概率dp 高斯消元

    大前提,把两个点的组合看成一种状态 x 两种思路 O(n^7) f[x]表示在某一个点的前提下,这个状态经过那个点的概率,用相邻的点转移状态,高斯一波就好了 O(n^6) 想象成臭气弹,这个和那个的区 ...

  3. 支持jsonP的Controller写法

    支持jsonP的Controller写法 package com.taotao.sso.controller; import org.apache.commons.lang3.StringUtils; ...

  4. BZOJ 2457 双端队列(思维

    2457: [BeiJing2011]双端队列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 582  Solved: 253[Submit][Sta ...

  5. 解析json方式之net.sf.json

    前面转载了json解析的技术:fastjson,今天说下另外一种技术. 下载地址 本次使用版本:http://sourceforge.net/projects/json-lib/files/json- ...

  6. 动态规划&字符串:最长公共子串

    还是直接上转移方程: 动规只能解决O(n^2)的最长公共子串问题 使用后缀数组或者SAM可以高效地解决这个问题 所以,对于这个问题,动规的代码就不给出了 直接给出SAM的实现,也为以后学习SAM打下一 ...

  7. 【Foreign】划分序列 [线段树][DP]

    划分序列 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 9 4 ...

  8. mongo语法和mysql语法对比学习

    我们总是在对比中看到自己的优点和缺点,对于mongodb来说也是一样,对比学习让我们尽快的掌握关于mongodb的基础知识. mongodb与mysql命令对比 关系型数据库一般是由数据库(datab ...

  9. Type of flip id

    http://www.haskell.org/pipermail/beginners/2011-March/006477.html The point is that the type of id h ...

  10. JavaScript设置获取和设置属性的方法

    这篇文章主要介绍了JavaScript设置获取和设置属性的方法,学会使用getAttribute.setAttribute的用法,需要的朋友可以参考下   getAttribute 该方法用来获取元素 ...