Я говорю здесь, основываясь на последних битах, которые доступны на Codeplex ASP.NET Web Stack repo.
Порядок заказанных пользователем приказов к каталогу. Позвольте мне объяснить:
Предположим, у нас есть два обработчика сообщений: 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
в качестве второго, другими словами ФИФО.
Если мы посмотрим на немного под капотом внутри рамки, то мы увидим, что Initialize
метод экземпляра HttpServer
является вызовом CreatePipeline
метод System.Net.Http.HttpClientFactory
(который был ранее известный как HttpPipelineFactory.Create
способом, как указано Али.) CreatePipeline
метод принимает два параметра: HttpMessageHandler
и IEnumerable<DelegatingHandler>
. HttpServer.Initialize
метод проходит System.Web.Http.Dispatcher.HttpControllerDispatcher
для HttpMessageHandler
параметр как последний HttpMessageHandler
внутри цепи и HttpConfiguration.MessageHandlers для параметра IEnumerable<DelegatingHandler>
.
Что происходит внутри метода 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
является обработчик последнего сообщения для запуска внутри цепочки.
Что касается вызова дважды, это не совсем так. С другой стороны, обработчик сообщения не будет вызываться дважды, метод продолжения, который вы предоставите, будет, с другой стороны. Это зависит от вас, чтобы это произошло. Если вы предоставляете обратный вызов (другими словами, продолжение), ваши обработчики сообщений будут вызваны на обратном пути к клиенту с генерируемым ответным сообщением, с которым вы можете играть.
Например, давайте предположим, что следующие два являются обработчики сообщений мы зарегистрировали выше:
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
будет вторым.
Вот что я думал. Я не думаю, что он поддерживает концепцию поставщиков. Как интерфейс IFilterprovider в MVC. – Darren
Я согласен с тем, что материал «Async/ContinueWith» заставляет его чувствовать себя гнездившимися куклами. На мой взгляд, более точно, чтобы описать их как упорядоченное, как это делает MS. Каждый обработчик вызывается дважды - один раз на пути в (в порядке зарегистрированного) и один раз выход в обратном порядке. Третья диаграмма в следующей статье дает понять. Http://www.asp.net/web-api/overview/working-with-http/http-message-handlers – EBarr