您的位置:首页 > 编程语言 > ASP

[译]Writing Custom Middleware in ASP.NET Core 1.0

2016-07-26 17:29 1031 查看
原文: 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的顺序非常重要

本文源码-github
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: