解读ASP.NET 5 & MVC6系列教程(6):Middleware详解

2019-05-22 14:44:59于海丽
HttpResponse在ASP.NET 5中都是重新定义的新类型。

Middleware的定义

既然每个middleare都是Func<RequestDelegate, RequestDelegate>的一个实例,那是不是Middleware的定义要满足一个规则?是继承于一个抽象基类还是借口?通过翻查相关的代码,我们看到,Middleware是基于约定的形式来定义的,具体约定规则如下:

构造函数的第一个参数必须是处理管线中的下一个处理函数,即RequestDelegate;必须有一个 Invoke 函数, 并接受上下文参数(即HttpContent), 然后返回 Task;

示例如下:

public class MiddlewareName
{
 RequestDelegate _next;

 public MiddlewareName(RequestDelegate next)
 {
  _next = next;// 接收传入的RequestDelegate实例
 }

 public async Task Invoke(HttpContext context)
 {
  // 处理代码,如处理context.Request中的内容

  Console.WriteLine("Middleware开始处理");

  await _next(context);

  Console.WriteLine("Middleware结束处理");

  // 处理代码,如处理context.Response中的内容
 }
}

通过该模板代码可以看到,首先一个Middleware的构造函数要接收一个RequestDelegate的实例,先保存在一个私有变量里,然后通过调用Invoke方法(并接收HttpContent实例)并返回一个Task,并且在调用Invoke的方法中,要通过await _next(context);语句,链式到下一个Middleware上,我们的处理代码主要就是在链式语句的前后执行相关的代码。

举个例子,如果我们要想记录页面的执行时间,首先,我们先定义一个TimeRecorderMiddleware,代码如下:

public class TimeRecorderMiddleware
{
 RequestDelegate _next;

 public TimeRecorderMiddleware(RequestDelegate next)
 {
  _next = next;
 }

 public async Task Invoke(HttpContext context)
 {
  var sw = new Stopwatch();
  sw.Start();


  await _next(context);

  var newDiv = @"<div id=""process"">页面处理时间:{0} 毫秒</div></body>";
  var text = string.Format(newDiv, sw.ElapsedMilliseconds);
  await context.Response.WriteAsync(text);
 }
}

Middleware的注册有很多种方式,如下是实例型注册代码:

app.Use(next => new TimeRecorderMiddleware(next).Invoke);

或者,你也可以使用UseMiddleware扩展方法进行注册,示例如下:

app.UseMiddleware<TimeRecorderMiddleware>();
//app.UseMiddleware(typeof(TimeRecorderMiddleware)); 两种方式都可以

当然,你也可以定义一个自己的扩展方法用于注册该Middleware,代码如下:

public static IApplicationBuilder UseTimeRecorderMiddleware(this IApplicationBuilder app)
{
 return app.UseMiddleware<TimeRecorderMiddleware>();
}

最后在Startup类的Configure方法内进行注册,代码如下: