当我们看到一个请求是如何被处理的时候,我们在第 3 章中提到了消息处理器。现在,我们更深入地了解它们是如何实现的,以及它们如何为我们的应用程序添加功能。
消息处理器的典型行为是获取请求,对请求进行一些操作,然后将其传递给链中的下一个处理器。
消息处理器只是一个继承了HttpMessageHandler
抽象类的类。这个类的接口,如果去掉IDisposable
接口,只是一个接收HttpRequestMessage
返回HttpResponseMessage
的方法。
事实上,消息处理器的目的只是接收请求消息(HttpRequestMessage
)并返回响应(HttpResponseMessage
)。ASP.NET 网络应用编程接口将这些处理器组成一个链,其中每个处理器都是对下一个的引用(通过InnerHandler
属性),这样处理器就可以执行调用并将结果传递给下一个。最终的结果就像一个洋葱,被请求和响应消息遍历。
消息处理器有几种使用方式。例如,我们可以构建一个消息处理器,在响应中添加一个定制的头。代码非常简单,反映了架构的简单性:
public class CustomHeaderMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync
(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
request.Headers.Add("X-My-custom-Header", "this is a custom header");
return base.SendAsync(request,
cancellationToken);
}
}
前面的代码演示了如何创建一个处理器,该处理器只需在请求头(X-My-custom-Header
)中添加一个新条目,并将调用传递给基类进行进一步处理。
我们继承自DelegatingHandler
类,该类已经实现了管理对链中其他处理器的传递调用的机制。DelegatingHandler
本身来源于HttpMessageHandler
。
处理器也可以用来记录请求或错误:
public class LogMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync
(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
HttpResponseMessage response = await base.SendAsync(request,
cancellationToken);
if (!response.IsSuccessStatusCode)
{
// Log the error.
}
return response;
}
}
在这种情况下,我们将调用传递给基类来执行,因为我们需要知道调用是成功的还是抛出了错误。我们得到响应,并在出现错误时写入日志。
定义后,需要将处理器添加到配置中,以便 ASP.NET 网络应用编程接口可以在执行管道中使用它:
// in WebApiConfig.cs
config.MessageHandlers.Add(new CustomHeaderMessageHandler());
config.MessageHandlers.Add(new LogMessageHandler());
我们必须考虑注册处理器的顺序很重要,因为它是以自上而下的方式执行的。也就是说,首先为请求消息调用第一个条目,然后为响应消息调用最后一个条目(如上图所述)。
消息处理器也可以按路由注册,而不是全局应用。每个路由注册一个处理器意味着该处理器只对某些请求发生:
IHttpRoute route = config.Routes.CreateRoute(
routeTemplate: "api/Posts/{id}",
defaults: new HttpRouteValueDictionary("route"),
constraints: null,
dataTokens: null,
handler: new CustomHeaderMessageHandler());
config.Routes.Add("WithHandler",route);
在这种情况下,我们只对路线模板中显示的PostsController
使用CustomHeaderMessageHandler
。
处理器在 ASP.NET 网络应用编程接口的架构中起着核心作用。在服务之外修改请求和响应的能力打开了有趣的场景,并提供了扩展默认框架行为的可能性。
在本章中,我们了解了关于处理器的一些基本背景信息,以及如何针对特定情况实现一些自定义处理器。