我在此基础上可在 Codeplex上的ASP.NET Web堆栈回购最新位在这里谈论。
订单由用户控制,在这里没有任意的顺序。让我来解释:
比方说,我们有两个消息处理程序:MyMessageHandler
和MyMessageHandler2
。假设我们把它们注册为如下:
protected void Application_Start(object sender, EventArgs e) {
RouteConfig.RegisterRoutes(GlobalConfiguration.Configuration.Routes);
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyMessageHandler());
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyMessageHandler2());
}
你期望在这里有什么是对MyMessageHandler
第一和MyMessageHandler2
运行的第二个,换句话说FIFO。
如果我们看一下框架内的引擎盖下了一点点,我们将看到HttpServer
实例Initialize
方法调用的System.Net.Http.HttpClientFactory
CreatePipeline
方法(以前称为HttpPipelineFactory.Create
方法,阿里表示。)CreatePipeline
方法接受两个参数:HttpMessageHandler
和IEnumerable<DelegatingHandler>
。 HttpServer.Initialize
方法传递System.Web.Http.Dispatcher.HttpControllerDispatcher
为HttpMessageHandler
参数作为链和HttpConfiguration.MessageHandlers为IEnumerable<DelegatingHandler>
参数内的最后HttpMessageHandler
。
的CreatePipeline
方法里面会发生什么情况是很聪明IMO:
public static HttpMessageHandler CreatePipeline(HttpMessageHandler innerHandler, IEnumerable<DelegatingHandler> handlers)
{
if (innerHandler == null)
{
throw Error.ArgumentNull("innerHandler");
}
if (handlers == null)
{
return innerHandler;
}
// Wire handlers up in reverse order starting with the inner handler
HttpMessageHandler pipeline = innerHandler;
IEnumerable<DelegatingHandler> reversedHandlers = handlers.Reverse();
foreach (DelegatingHandler handler in reversedHandlers)
{
if (handler == null)
{
throw Error.Argument("handlers", Properties.Resources.DelegatingHandlerArrayContainsNullItem, typeof(DelegatingHandler).Name);
}
if (handler.InnerHandler != null)
{
throw Error.Argument("handlers", Properties.Resources.DelegatingHandlerArrayHasNonNullInnerHandler, typeof(DelegatingHandler).Name, "InnerHandler", handler.GetType().Name);
}
handler.InnerHandler = pipeline;
pipeline = handler;
}
return pipeline;
}
正如你所看到的,消息处理顺序颠倒,并创建Matryoshka doll但这里要小心:这是确保HttpControllerDispatcher
是最后一个消息处理程序在链中运行。
至于调用两次的问题,实际上并不是真的。另一方面,消息处理程序不会被调用两次,您将提供的继续方法将会是。这取决于你做到这一点。如果你提供了一个回调(换句话说,就是continuation),你的消息处理程序将在返回给客户端的路上被调用,并生成你可以使用的响应消息。
例如,假设以下两个是我们在上面已经注册的消息处理程序:
public class MyMessageHandler : DelegatingHandler {
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) {
//inspect request here
return base.SendAsync(request, cancellationToken).ContinueWith(task => {
//inspect the generated response
var response = task.Result;
return response;
});
}
}
这是另一种:
public class MyMessageHandler2 : DelegatingHandler {
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) {
//inspect request here
return base.SendAsync(request, cancellationToken).ContinueWith(task => {
//inspect the generated response
var response = task.Result;
return response;
});
}
}
正如我们所提供的延续,我们的消息处理程序将按照FILO顺序返回到客户端。因此,MyMessageHandler2
内的延续方法将成为第一个在回来的路上被调用的方法,MyMessageHandler
内的第二个将成为第二个。
这就是我的想法。我认为它也不支持提供者的概念。像MVC中的IFilterProvider接口一样。 – Darren 2012-04-21 06:53:33
我同意'Async/ContinueWith'的东西使它感觉像嵌套娃娃。在我看来,更准确地说,就像MS那样,按照有序来描述它们。每个处理程序都被调用两次 - 一次在注册的顺序中,一次以相反顺序排出。下面的文章中的第三个图表明确了它。http://www.asp.net/web-api/overview/working-with-http/http-message-handlers – EBarr 2012-04-22 03:32:14