Autofac - DelegatingHandler (HttpMessageHandler) Registration

5k views Asked by At

I have a custom DelegatingHandler in a class library that I need to register with Autofac. The webapi host resolves it's dependencies on runtime, so the host has no references to this library.

public class LocalizationHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
    {}
}

On my Autofac initializer class I've tried things like:

protected override void Load( ContainerBuilder builder )
{
     builder.RegisterType<LocalizationHandler>();
     builder.Register(c => new LocalizationHandler());
}

The normal way to register such handlers within the host would be:

public static void Register(HttpConfiguration httpConfiguration)
{        
    httpConfiguration.MapHttpAttributeRoutes();          
    httpConfiguration.MessageHandlers.Add(new LocalizationHandler());
}

But I don't have access to the host project here. Any ideas how to inject the handler over the ContainerBuilder?

2

There are 2 answers

1
endeffects On BEST ANSWER

Here is my solution for a late binding:

Global.asax

protected void Application_Start()
{
    List<DelegatingHandler> messageHandlers = GlobalConfiguration.Configuration.DependencyResolver.GetMessageHandlers();
    messageHandlers.ForEach(GlobalConfiguration.Configuration.MessageHandlers.Add);
}

Helper

public static class DependencyHelper
{
    public static List<DelegatingHandler> GetMessageHandlers(this IDependencyResolver dependencyResolver)
    {
        return dependencyResolver.GetServices(typeof (DelegatingHandler)).Cast<DelegatingHandler>().ToList();
    }
}

Library

protected override void Load(ContainerBuilder builder)
{
    builder.RegisterType<GlobalLocalizationHandler>().As<DelegatingHandler>();
}
1
Cyril Durand On

It seems that you can't inject HttpMessageHandler in Web API

Given the message handler is passed as instance and being initialized once for the entire service. I think it is easier to have user code inject the dependency themselves first and register the instance with http configuration. This allow people to write custom message handler that has constructor but do not need dependency injection as well. The current model is more flexible.

>> http://aspnetwebstack.codeplex.com/workitem/62

But you can create Proxy that will do what you want. For example :

public class ProxyDelegatingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        IEnumerable<DelegatingHandler> innerHandlers = 
            request.GetDependencyScope()
                   .GetServices(typeof(DelegatingHandler))
                   .OfType<DelegatingHandler>();

        HttpMessageHandler handler = this.InnerHandler;
        foreach (DelegatingHandler innerHandler in innerHandlers)
        {
            innerHandler.InnerHandler = handler;
            handler = innerHandler;
        }

        HttpMessageInvoker invoker = new HttpMessageInvoker(handler, false);
        return invoker.SendAsync(request, cancellationToken);
    }
}

And register your handlers like this :

        builder.RegisterType<X1Handler>().As<DelegatingHandler>().InstancePerRequest();
        builder.RegisterType<X2Handler>().As<DelegatingHandler>().InstancePerRequest();

        config.MessageHandlers.Add(new ProxyDelegatingHandler());