[译]Writing Custom Middleware in ASP.NET Core 1.0
原文: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/
Middleware是ASP.NET Core 1.0的新特性。Middleware用来检测request和response的输入输出。
什么是Middleware?
Middleware是用来检测request和response的组件。Pipeline如下:

Middleware可以用来替代HttpModules和HttpHandlers的工作。
默认的Middleware
使用VS创建的ASP.NET Core的应用,默认就使用了Middleware.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink(); //Middleware
app.UseDeveloperExceptionPage(); //Middleware
}
else
{
app.UseExceptionHandler("/Home/Error"); //Middleware
}
app.UseIISPlatformHandler(); //Middleware
app.UseStaticFiles(); //Middleware
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
}); //Middleware
}
在上面的方法中,那些app.UserX(),就意味着使用了ASP.NET默认的Middleware组件。
自定义Middleware组件
Middleware组件和其他的class基本一样, 不同的是Middleware有一个类型为RequestDelegate的私有属性,如下:
public class AuthorizationMiddleware
{
private readonly RequestDelegate _next;
public AuthorizationMiddleware(RequestDelegate next)
{
_next = next;
}
}
_next属性是一个委托,为Pipeline中下一个组件所用。 每个Middleware都实现一个async任务:
public async Task Invoke(HttpContext context)
{
await _next.Invoke(context);
}
Middleware任务
下面我们新建一个Middleware用于检查HTTP头,如果HTTP头有"X-Not-Authorized",直接返回401。代码如下:
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains("X-Not-Authorized"))
{
context.Response.StatusCode = 401; //Unauthorized
return;
}
await _next.Invoke(context);
}
Middleware可以做许多事。例如:
- 你想检查每一次request,如果request请求的是一个图片,将请求redirect的一个图片handler。
- 你想有一个组件用来记录每一次http请求
- ..........
其他Middleware的例子
定义一个RequestHeaderMiddleware
public class RequestHeaderMiddleware
{
private readonly RequestDelegate _next;
public RequestHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains("X-Cancel-Request"))
{
context.Response.StatusCode = 500;
return;
}
await _next.Invoke(context);
if (context.Request.Headers.Keys.Contains("X-Transfer-By"))
{
context.Response.Headers.Add("X-Transfer-Success", "true");
}
}
}
这个Middleware可以做两件事情:
- 如果HTTP请求头包含"X-Cancel-Request"那么服务器之间返回500
- 如果HTTP请求头包含"X-Transfer-By"服务器给响应头加上"X-Transfer-Success"
定义一个ProcessingTimeMiddleware
public class ProcessingTimeMiddleware
{
private readonly RequestDelegate _next;
public ProcessingTimeMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var watch = new Stopwatch();
watch.Start();
await _next(context);
context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() });
}
}
上面的Middleware用到了Stopwatch,这个组件记录请求响应的时间,并将其作为响应头返回给客户。
添加Middeware到HTTP管道中
有两种方法将Middleware注册到pipeline中。 一种是在Startup文件的Configure方法中调用IApplicationBuilder的UseMiddleware方法:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseMiddleware<AuthorizationMiddleware>();
...
}
另一种是我推荐使用的方法,为每个你想注册的Middleware添加一个扩展方法,然后在Configure中调用。代码如下:
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseRequestHeaderMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestHeaderMiddleware>();
}
public static IApplicationBuilder UseAuthorizationMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<AuthorizationMiddleware>();
}
public static IApplicationBuilder UseProcessingTimeMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ProcessingTimeMiddleware>();
}
}
现在可以在Starup中使用这些扩展方法了(仔细读下面的代码,它包含一个Bug)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseProcessingTimeMiddleware();
app.UseRequestHeaderMiddleware();
app.UseAuthorizationMiddleware();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
发现这个Bug了没?
当你注册Middleware时,你添加Middleware的顺序非常重要。上面的代码中,我们首先添加了ProcessingTimeMiddleware, 然后添加RequestHeaderMiddleware,最后添加的是AuthorizationMiddleware。 这个顺序恰好搞反了。 正确的顺序如下:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseAuthorizationMiddleware();
app.UseRequestHeaderMiddleware();
app.UseProcessingTimeMiddleware();
...
}
总结
记住下面3点:
- Middleware能让我们完全控制Http管道
- Middleware可以处理验证,重定向,HTTP头,甚至取消HTTP请求
- 在Startup中注册Middleware的顺序非常重要
[译]Writing Custom Middleware in ASP.NET Core 1.0的更多相关文章
- [转]Writing Custom Middleware in ASP.NET Core 1.0
本文转自:https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/ One of the new ...
- [译]ASP.NET Core 2.0 系列文章目录
基础篇 [译]ASP.NET Core 2.0 中间件 [译]ASP.NET Core 2.0 带初始参数的中间件 [译]ASP.NET Core 2.0 依赖注入 [译]ASP.NET Core 2 ...
- ASP.NET Core 3.0 自动挡换手动挡:在 Middleware 中执行 Controller Action
最近由于发现奇怪的 System.Data.SqlClient 性能问题(详见之前的博文),被迫提前了向 .NET Core 3.0 的升级工作(3.0 Preview 5 中问题已被修复).郁闷的是 ...
- [译]ASP.NET Core 2.0 中间件
问题 如何创建一个最简单的ASP.NET Core中间件? 答案 使用VS创建一个ASP.NET Core 2.0的空项目,注意Startup.cs中的Configure()方法: public vo ...
- [译]ASP.NET Core 2.0 带初始参数的中间件
问题 如何在ASP.NET Core 2.0向中间件传入初始参数? 答案 在一个空项目中,创建一个POCO(Plain Old CLR Object)来保存中间件所需的参数: public class ...
- [译]ASP.NET Core 2.0 全局配置项
问题 如何在 ASP.NET Core 2.0 应用程序中读取全局配置项? 答案 首先新建一个空项目,并添加两个配置文件: 1. appsettings.json { "Section1&q ...
- [译]ASP.NET Core 2.0 机密配置项
问题 如何在ASP.NET Core 2.0中保存机密配置项(不用将其暴露给源代码管理器)? 答案 创建一个ASP.NET Core 2.0空项目,在项目节点上点击右键,并点击菜单项 - 管理用户机密 ...
- [译]ASP.NET Core 2.0 会话状态
问题 如何在ASP.NET Core 2.0中存储会话状态? 答案 创建一个空项目,修改Startup类的ConfigureServices()方法,添加会话状态服务和它后台的存储服务: public ...
- [译]ASP.NET Core 2.0 本地文件操作
问题 如何在ASP.NET Core 2.0中受限地访问本地目录和文件信息? 答案 新建一个空项目,修改Startup类,添加访问本地文件所需的服务: public void ConfigureSer ...
随机推荐
- 禁用Windows重复数据删除
重复数据删除,可以减少磁盘占用,但使用不当也有可能增加IO,另外,也为此功能会将硬盘分块,所以当硬盘占用较高时,进行碎片整理也比较困难,所以有时需要禁用掉重复数据删除功能,并解除重复数据的优化,可以通 ...
- mac下openresty安装
//openresty安装 http://openresty.org/ brew updatebrew install pcre openssl ./configure --prefix=/usr/l ...
- Nhibernate mapping 文件编写
生成工具软件 现在生成工具软件有很多了,例如商业软件:NMG.CodeSmith.Visual NHibernate,开源软件:MyGeneration.NHibernate Modeller.AjG ...
- Softreference | WeakReference
转自:http://blog.csdn.net/kavendb/article/details/5935577 本文介绍对象的强.软.弱和虚引用的概念.应用及其在UML中的表示. 1.对象的强.软.弱 ...
- [LeetCode] Sparse Matrix Multiplication 稀疏矩阵相乘
Given two sparse matrices A and B, return the result of AB. You may assume that A's column number is ...
- const 引起的BUG
今天白天出现了碰见了一个问题,隐藏得比较深,这里记录一下. 初衷很简单,就是要更改改一个数据库的链接名,这个链接名是放在数据层public const string connDB="conn ...
- SQLite3源程序分析之分析器的生成
1.概述 Lemon是一个LALR(1)文法分析器生成工具,与bison和yacc类似,是一个可以独立于SQLite使用的开源的分析器生成工具.而且它使用与yacc(bison)不同的语法规则,可以减 ...
- Objective-c快速入门
对象(Class)的声明和定义 和其他的语言不同,OC的对象创建分为两个部分.声明部分(@interface)和实现部分(@implementation),且它们都必须使用@end结束. 对象的声明( ...
- CentOS安装Maven
现有的一个项目使用了Maven来管理,源代码放到了Subversion中.虽然Maven管理项目很方便,但是部署起来还是很麻烦的.先要在本地生成项目jar包,上传到服务器,然后再重启服务.如果在服务器 ...
- Mysql字符串字段判断是否包含某个字符串的3种方法
方法一: SELECT * FROM users WHERE emails like "%b@email.com%"; 方法二: 利用MySQL 字符串函数 find_in_set ...