using System.Threading.Tasks; public class CustomResponseHeader: IMiddleware { // 使用构造函数完成服务依赖的定义 public CustomResponseHeader() { } public Task InvodeAsync(HttpContextSample context, RequestDelegate next) { context.Output.AppendLine("From Custom Middleware."); return next(context); } }
这更好看懂了,可是它怎么变成那个 Func<RequestDelegate, RequestDelegate> 呢?
在演示程序中使用该中间件。
List<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>(); _components.Add(middleware1); _components.Add(middleware2); var middleware3 = new CustomResponseHeader(); Func<RequestDelegate, RequestDelegate> middleware3 = next => { return (HttpContextSample context) => { // 中间件 3 的处理 var result = middleware3.InvodeAsync(context, next); return result; }; }; _components.Add(middleware3);
这样开发者可以使用熟悉的对象方式开发中间件,而系统内部自动根据你的定义,生成出来一个 Func<RequestDelegate, RequestDelegate> 形式的中间件。
ASP.NET Core 使用该类型中间件的形式如下所示,这是提供了一个方便的扩展方法来完成这个工作。
.UseMiddleware<CustomResponseHeader>();
按照约定定义中间件
除了实现 IMiddleware 这个接口,还可以使用约定方式来创建中间件。
按照约定定义中间件不需要实现某个预定义的接口或者继承某个基类,而是需要遵循一些约定即可。约定主要体现在如下几个方面:
中间件需要一个公共的有效构造函数,该构造函数必须包含一个类型为 RequestDelegate 类型的参数。它代表后继的中间件处理函数。构造函数不仅可以包含任意其它参数,对 RequestDelegate 参数出现的位置也没有任何限制。
针对请求的处理实现再返回类型为 Task 的 InvokeAsync() 方法或者同步的 Invoke() 方法中,方法的第一个参数表示当前的请求上下文 HttpContext 对象,对于其他参数,虽然约定并未进行限制,但是由于这些参数最终由依赖注入框架提供,所以,相应的服务注册必须提供。
构造函数和 Invoke/InvokeAsync 的其他参数由依赖关系注入 (DI) 填充。
using System.Threading.Tasks; public class RequestCultureMiddleware { private readonly RequestDelegate _next; public RequestCultureMiddleware (RequestDelegate next) { _next = next; } public async Task InvokeAsync (HttpContextSample context) { context.Output.AppendLine("Middleware 4 Processing."); // Call the next delegate/middleware in the pipeline await _next (context); } }
在演示程序中使用按照约定定义的中间件。
Func<RequestDelegate, RequestDelegate> middleware4 = next => { return (HttpContextSample context) => { var step4 = new RequestCultureMiddleware(next); // 中间件 4 的处理 var result = step4.InvokeAsync (context); return result; }; }; _components.Add (middleware4);
在 ASP.NET Core 中使用按照约定定义的中间件语法与使用强类型方式相同:
.UseMiddleware<RequestCultureMiddleware >();
中间件的顺序
中间件安装一定顺寻构造成为请求处理管道,常见的处理管道如下所示:
实现 BeginRequest 和 EndRequest
理解了请求处理管道的原理,下面看它的一个应用。
在 ASP.NET 中我们可以使用预定义的 Begin_Request 和 EndRequest 处理步骤。
现在整个请求处理管道都是我们自己来进行构建了,那么怎么实现 Begin_Request 和 EndRequest 呢?使用中间件可以很容易实现它。
首先,这两个步骤是请求处理的第一个和最后一个步骤,显然,该中间件必须是第一个注册到管道中的。
所谓的 Begin_Request 就是在调用 next() 之间的处理了,而 End_Request 就是在调用 next() 之后的处理了。在 https://stackoverflow.com/questions/40604609/net-core-endrequest-middleware 中就有一个示例,我们将它修改一下,如下所示:
public class BeginEndRequestMiddleware { private readonly RequestDelegate _next; public BeginEndRequestMiddleware(RequestDelegate next) { _next = next; } public void Begin_Request(HttpContext context) { // do begin request } public void End_Request(HttpContext context) { // do end request } public async Task Invoke(HttpContext context) { // Do tasks before other middleware here, aka 'BeginRequest' Begin_Request(context); // Let the middleware pipeline run await _next(context); // Do tasks after middleware here, aka 'EndRequest' End_Request(); } }
Register