ASP.NET Core 2 学习笔记(三)中间件
之前ASP.NET中使用的HTTP Modules及HTTP Handlers,在ASP.NET Core中已不复存在,取而代之的是Middleware。Middleware除了简化了HTTP Modules/Handlers的使用方式,还带入了Pipeline的概念。
本篇将介绍ASP.NET Core的Middleware概念及用法。
Middleware 概念
ASP.NET Core在Middleware的官方说明中,使用了Pipeline这个名词,意指Middleware像水管一样可以串联在一起,所有的Request及Response都会层层经过这些水管。
用图例可以很容易理解,如下图:

App.Use
Middleware的注册方式是在Startup.cs的Configure对IApplicationBuilder使用Use方法注册。
大部分扩展的Middleware也都是以Use开头的方法注册,例如:
- UseMvc():MVC的Middleware
- UseRewriter():URL rewriting的Middleware
一个简单的Middleware 范例。如下:
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; namespace MyWebsite
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.Use(async (context, next) =>
{
await context.Response.WriteAsync("First Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("First Middleware out. \r\n");
}); app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Second Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("Second Middleware out. \r\n");
}); app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Third Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("Third Middleware out. \r\n");
}); app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World! \r\n");
});
}
}
}
用浏览器打开网站任意连结,输出结果:
First Middleware in.
Second Middleware in.
Third Middleware in.
Hello World!
Third Middleware out.
Second Middleware out.
First Middleware out.
在Pipeline的概念中,注册顺序是很重要的事情。请求经过的顺序一定是先进后出。
Request 流程如下图:

Middleware 也可以作为拦截使用,如下:
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; namespace MyWebsite
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.Use(async (context, next) =>
{
await context.Response.WriteAsync("First Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("First Middleware out. \r\n");
}); app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Second Middleware in. \r\n"); // 水管阻塞,封包不往后送
var condition = false;
if (condition)
{
await next.Invoke();
}
await context.Response.WriteAsync("Second Middleware out. \r\n");
}); app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Third Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("Third Middleware out. \r\n");
}); app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World! \r\n");
});
}
}
}
输出结果:
First Middleware in.
Second Middleware in.
Second Middleware out.
First Middleware out.
在Second Middleware 中,因为没有达成条件,所以封包也就不在往后面的水管传送。流程如图:

App.Run
Run是Middleware的最后一个行为,以上面图例来说,就是最末端的Action。
它不像Use能串联其他Middleware,但Run还是能完整的使用Request及Response。
App.Map
Map是能用来处理一些简单路由的Middleware,可依照不同的URL指向不同的Run及注册不同的Use。
新增一个路由如下:
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; namespace MyWebsite
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.Use(async (context, next) =>
{
await context.Response.WriteAsync("First Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("First Middleware out. \r\n");
}); // app.Use(async (context, next) =>
// {
// await context.Response.WriteAsync("Second Middleware in. \r\n"); // // 水管阻塞,封包不往后送
// var condition = false;
// if (condition)
// {
// await next.Invoke();
// }
// await context.Response.WriteAsync("Second Middleware out. \r\n");
// }); app.Map("/second", mapApp =>
{
mapApp.Use(async (context, next) =>
{
await context.Response.WriteAsync("Second Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("Second Middleware out. \r\n");
});
mapApp.Run(async context =>
{
await context.Response.WriteAsync("Second. \r\n");
});
}); app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Third Middleware in. \r\n");
await next.Invoke();
await context.Response.WriteAsync("Third Middleware out. \r\n");
}); app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World! \r\n");
});
}
}
}
开启网站任意连结,会显示:
First Middleware in.
Third Middleware in.
Hello World!
Third Middleware out.
First Middleware out.
开启网站http://localhost:5000/second,则会显示:
First Middleware in.
Second Middleware in.
Second.
Second Middleware out.
First Middleware out.
创建Middleware 类
如果Middleware全部都写在Startup.cs,代码将很难维护,所以应该把自定义的Middleware逻辑独立出来。
建立Middleware类不需要额外继承其它类或接口,一般的类即可,例子如下:
FirstMiddleware.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; namespace MyWebsite
{
public class FirstMiddleware
{
private readonly RequestDelegate _next; public FirstMiddleware(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext context)
{
await context.Response.WriteAsync($"{nameof(FirstMiddleware)} in. \r\n"); await _next(context); await context.Response.WriteAsync($"{nameof(FirstMiddleware)} out. \r\n");
}
}
}
全局注册
在Startup.Configure注册Middleware就可以套用到所有的Request。如下:
Startup.cs
// ...
public class Startup
{
// ...
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<FirstMiddleware>();
// ...
}
}
局部注册
Middleware 也可以只套用在特定的Controller 或Action。注册方式如下:
Controllers\HomeController.cs
// ..
[MiddlewareFilter(typeof(FirstMiddleware))]
public class HomeController : Controller
{
// ... [MiddlewareFilter(typeof(SecondMiddleware))]
public IActionResult Index()
{
// ...
}
}
Extensions
大部分扩展的Middleware都会用一个静态方法包装,如:UseMvc()、UseRewriter()等。
自定义的Middleware当然也可以透过静态方法包,范例如下:
Extensions\CustomMiddlewareExtensions.cs
using Microsoft.AspNetCore.Builder; namespace MyWebsite
{
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseFirstMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<FirstMiddleware>();
}
}
}
注册Extension Middleware 的方式如下:
Startup.cs
// ...
public class Startup
{
// ...
public void Configure(IApplicationBuilder app)
{
app.UseFirstMiddleware();
// ...
}
}
参考
ASP.NET Core Middleware Fundamentals
Creating Custom Middleware In ASP.Net Core
老司机发车啦:https://github.com/SnailDev/SnailDev.NETCore2Learning
ASP.NET Core 2 学习笔记(三)中间件的更多相关文章
- Asp .Net core 2 学习笔记(2) —— 中间件
这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...
- sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)
sql server 关于表中只增标识问题 由于我们系统时间用的过长,数据量大,设计是采用自增ID 我们插入数据的时候把ID也写进去,我们可以采用 关闭和开启自增标识 没有关闭的时候 ,提示一下错 ...
- Asp.Net Core WebApi学习笔记(四)-- Middleware
Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...
- ASP.NET Core 2 学习笔记(七)路由
ASP.NET Core通过路由(Routing)设定,将定义的URL规则找到相对应行为:当使用者Request的URL满足特定规则条件时,则自动对应到相符合的行为处理.从ASP.NET就已经存在的架 ...
- ASP.NET Core 2 学习笔记(十三)Swagger
Swagger也算是行之有年的API文件生成器,只要在API上使用C#的<summary />文件注解标签,就可以产生精美的线上文件,并且对RESTful API有良好的支持.不仅支持生成 ...
- ASP.NET Core 2 学习笔记(十二)REST-Like API
Restful几乎已算是API设计的标准,通过HTTP Method区分新增(Create).查询(Read).修改(Update)和删除(Delete),简称CRUD四种数据存取方式,简约又直接的风 ...
- ASP.NET Core 2 学习笔记(十)视图
ASP.NET Core MVC中的Views是负责网页显示,将数据一并渲染至UI包含HTML.CSS等.并能痛过Razor语法在*.cshtml中写渲染画面的程序逻辑.本篇将介绍ASP.NET Co ...
- ASP.NET Core 2 学习笔记(一)开始
原文:ASP.NET Core 2 学习笔记(一)开始 来势汹汹的.NET Core似乎要取代.NET Framework,ASP.NET也随之发布.NET Core版本.虽然名称沿用ASP.NET, ...
- 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
本篇是在上一篇的基础上添加日志功能,并记录NLog在Asp.Net Core里的使用方法. 第一部分:默认Logger支持 一.project.json添加日志包引用,并在cmd窗口使用 dotnet ...
随机推荐
- C++的编译与连接
编译器的任务是把我们人类通常能够读懂的文本形式的 C 语言文件转化成计算机能明白的目标文件.1. 预编译生成的仍然是.c文件1)把"include"的文件拷贝到要编译的源文件中. ...
- phpStudy5——php导入其他php文件(php文件的引入)
前言: 通过前边几个例子,相信大家都会有一个疑惑了,就是每个请求数据库的php页面,都要写一次连接数据库的代码,这个肯定是有违代码复用原则的.那么怎么解决这个问题呢? 在php中可以通过include ...
- 使用VisualSVN Server搭建SVN服务器[xyytit]
使用 VisualSVN Server来实现主要的 SVN功能则要比使用原始的 SVN和 Apache相配合来实现源代码的 SVN管理简单的多,上手也没有那么复杂. 下面就看看详细的说明 Visual ...
- php 使用html5 XHR2 上传文件 进度显示
思路:只要我们知道上传文件的总大小,还有上传过程中上传文件的大小,那么就可以实现进度显示了. 在html5中,XMLHttpRequest对象,传送数据的时候,progress事件用来返回进度信息. ...
- php iframe 上传文件
我们通过动态的创建iframe,修改form的target,来实现无跳转的文件上传. 具体的实现步骤 1.捕捉表单提交事件 2.创建一个iframe 3.修改表单的target,指向iframe ...
- 在java工程中导入jar包的注意事项
在java工程中导入jar包后一定要bulid path,不然jar包不可以用.而在java web工程中导入jar包后可以不builld path,但最好builld path.
- JTemplate学习(四)
注释.自定方法.模板嵌套子模板.循环输出不同class <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "htt ...
- python的metaclass浅析-乾颐堂
元类一般用于创建类.在执行类定义时,解释器必须要知道这个类的正确的元类.解释器会先寻找类属性__metaclass__,如果此属性存在,就将这个属性赋值给此类作为它的元类.如果此属性没有定义,它会向上 ...
- 通过BeanShell获取UUID并将参数传递给Jmeter
有些HTTPS请求报文的报文体中包含由客户端生成的UUID,在用Jmeter做接口自动化测试的时候,因为越过了客户端,直接向服务器端发送报文,所以,需要在Jmeter中通过beanshell获取UUI ...
- jQuery nyroModal 插件遇到问题
nyroModal ver 1.6.2 弹出层插件 浏览更多 初始化大小问题 //页面加载完成后初始化 设置大小 $(function() { $.nyroModalSettings({ widt ...