[译]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 ...
随机推荐
- sys.dm_os_waiting_tasks 引发的疑问(中)
上一篇我们说了一下sys.dm_exec_requests 和 sys.dm_os_waiting_tasks 在获取并行等待的时候得不同结果,这一篇我们谈论下我的第二个疑问:为什么一个并行计划(4线 ...
- Linux 查看命令源码
一.简介 有时候想看看ls.cat.more等命令的源代码,本文介绍相应查看方法. 二.方法 参考: http://blog.csdn.net/silentpebble/article/details ...
- nth-of-type在选择class的时候需要注意的一个小问题
查了下w3和MDN的手册,没发现有这个说明,写篇随笔记下. 1..class:nth-of-type(n)在选择class的时候,如果在class前面插入x个同类型标签,n需要加上x <!DOC ...
- Django之Model操作
Django之Model操作 本节内容 字段 字段参数 元信息 多表关系及参数 ORM操作 1. 字段 字段列表 AutoField(Field) - int自增列,必须填入参数 primary_ke ...
- [LeetCode] Count Complete Tree Nodes 求完全二叉树的节点个数
Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...
- [LeetCode] First Missing Positive 首个缺失的正数
Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2,0] ...
- c#与JavaScript实现对用户名、密码进行RSA非对称加密
博主最近手上这个项目呢(就是有上百个万恶的复杂excel需要解析的那个项目,参见博客:http://www.cnblogs.com/csqb-511612371/p/4885930.html),由于是 ...
- Servlet学习笔记
在这里记录最重要的要点 1,tomcat-->conf-->server.xml里面的东西是什么?(tomcat怎么知道“谁”去处理客户端来的请求?) 最主要的是一个依赖的控制,换句话说什 ...
- C#事务
看了很多关于事务的概念,还是觉得维基百科上说的最好: 数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成. 一个数据库事务通常包含了一个序列的对数据库的读 ...
- JAVA之IO流(字符流)
字符流InputStreamReader和OutputStreamWriter是Writer和Read的子类:是字节流通向字符流的桥梁,也就是可以把字节流转化为字符流. InputStreamRead ...