ASP.NET Web API Message Handlers

Can I control the execution order of custom message handlers?

As an example, I could first process the logging handler, so I always log the request.

Besides adding the last log handler, I don't see how to do this.

config.MessageHandlers.Add(new CustomHandlerOne()); 
config.MessageHandlers.Add(new CustomHandlerTwo());
config.MessageHandlers.Add(new LoggingHandler());
+5
source share
3 answers

The order in which you register the handlers determines when they are called, but, as Aliostad points out, they work in the Russian doll model, so the first one is also called the last one, etc.

handlesr . , , .

+7

- AFAIK.

, , . HttpPipelineFactory ( ):

    public static HttpMessageHandler Create(IEnumerable<DelegatingHandler> handlers, HttpMessageHandler innerChannel)
    {
        if (innerChannel == null)
        {
            throw Error.ArgumentNull("innerChannel");
        }

        if (handlers == null)
        {
            return innerChannel;
        }

        // Wire handlers up
        HttpMessageHandler pipeline = innerChannel;
        foreach (DelegatingHandler handler in handlers)
        {
            if (handler == null)
            {
                throw Error.Argument("handlers", SRResources.DelegatingHandlerArrayContainsNullItem, typeof(DelegatingHandler).Name);
            }

            if (handler.InnerHandler != null)
            {
                throw Error.Argument("handlers", SRResources.DelegatingHandlerArrayHasNonNullInnerHandler, typeof(DelegatingHandler).Name, "InnerHandler", handler.GetType().Name);
            }

            handler.InnerHandler = pipeline;
            pipeline = handler;
        }

        return pipeline;
    }

, , , Russian Doll.

+3

, , 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 - , FIFO.

, , 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;
}

, , : 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;
        });
    }
}

As we continued, our message handlers will be returned on the way back to the client in FILO order. Thus, the continuation method inside MyMessageHandler2will be the first to be called on the return trip, and the second inside MyMessageHandlerwill be the second.

+3
source

All Articles