Estoy hablando aquí basado en los últimos bits que están disponibles en Codeplex ASP.NET Web Stack repo.
La orden es controlada por el usuario y no hay ningún orden arbitrario aquí. Permítanme explicar:
Digamos que tenemos dos manejadores de mensajes: MyMessageHandler
y MyMessageHandler2
. Suponiendo que se registren como a continuación:
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());
}
Lo que espera aquí es para el MyMessageHandler
ejecutar primero y MyMessageHandler2
como segunda, en otras palabras FIFO.
Si miramos un poco debajo de la capilla en el interior del marco, veremos que Initialize
método de la HttpServer
ejemplo invoca CreatePipeline
método de System.Net.Http.HttpClientFactory
(que se conocía anteriormente como HttpPipelineFactory.Create
método de los indicados Ali.) CreatePipeline
método acepta dos parámetros: HttpMessageHandler
y IEnumerable<DelegatingHandler>
. El método HttpServer.Initialize
está pasando System.Web.Http.Dispatcher.HttpControllerDispatcher
para el parámetro HttpMessageHandler
como el último HttpMessageHandler
dentro de la cadena y HttpConfiguration.MessageHandlers para el parámetro IEnumerable<DelegatingHandler>
.
¿Qué pasa dentro del método CreatePipeline
es muy inteligente 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;
}
Como se puede ver, el orden controlador de mensajes se invierte y el Matryoshka doll se crea pero tenga cuidado aquí: se asegura que HttpControllerDispatcher
es el último controlador de mensajes para ejecutar dentro de la cadena.
En cuanto a la llamada dos veces, en realidad no es del todo cierto. El manejador de mensajes no se llamará dos veces, el método de continuación que proporcionará va a ser, por otro lado. Depende de usted hacer que suceda. Si proporciona una devolución de llamada (en otras palabras, continuación), se llamará a sus manejadores de mensajes en el camino de regreso al cliente con el mensaje de respuesta generado con el que puede jugar.
Por ejemplo, vamos a suponer que los dos siguientes son los controladores de mensajes que hemos registrados anteriormente:
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;
});
}
}
Y este es el otro:
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;
});
}
}
Como hemos proporcionado continuación, nuestra los manejadores de mensajes serán llamados nuevamente en el camino de regreso al cliente en orden FILO. Por lo tanto, el método de continuación dentro del MyMessageHandler2
será el primero invocado en el camino de regreso y el que se encuentra dentro del MyMessageHandler
será el segundo.
Eso es lo que pensé. No creo que sea compatible con el concepto de proveedores tampoco. Al igual que la interfaz IFilterprovider en MVC. – Darren
Acepto que las cosas 'Async/ContinueWith' hacen que parezca muñecas de anidación. Es más preciso, en mi opinión, describirlos como ordenados, como lo hace MS. Cada controlador se llama dos veces: una vez en el camino hacia adentro (en el orden registrado) y una vez que sale en orden inverso. El tercer diagrama en el siguiente artículo lo deja claro .. http://www.asp.net/web-api/overview/working-with-http/http-message-handlers – EBarr