Autofac with SignalR and WebApi in Owin registration solution (without using container.Update)

In one of my Owin projects I want to use SignalR and WebApi. Autofac is used as Dependency injection, but somehow this results in a lot of registration problems. 

A lot of samples I've found where using the 

GlobalHost.ConnnectionManager.GetHubContext<>

Do not use GlobalHost in Owin

But the SignalR Autofac documentation clearly states that the GlobalHost static class cannot be used in a Owin project. You should use the IConnectionManager interface.

So I tried to create a Generic HubContextProvider<THubClient> which can be used to get the typed HubContext from the ConnectionManager.

public interface IHubContextProvider<THubClient>
        where THubClient : class
{
    IHubContext<THubClient> GetHubContext<THub>()
        where THub : Hub<THubClient>;
}

public class HubContextProvider<THubClient> : IHubContextProvider<THubClient>
        where THubClient : class
{
    private readonly IConnectionManager connectionManager;
    public HubContextProvider(IConnectionManager connectionManager)
    {
        this.connectionManager = connectionManager;
    }

    public IHubContext<THubClient> GetHubContext<THub>()
        where THub : Hub<THubClient>
    {
        return this.connectionManager.GetHubContext<THub, THubClient>();
    }
}

This class is used in Singleton HubHandlers, which are classes that are used to communicate back to the Clients subscribed. In the generic base class the property HubContext is set using the HubContextProvider.

Registration

In the Startup class of the application I created a ContainerBuilder and register all the types in the application. 

var builder = new ContainerBuilder();

// Register all typed needed in the application
// ....
builder.RegisterHubs(Assembly.GetExecutingAssembly());

var container = builder.Build();

Create Dependency Resolvers

For using WebApi and Autofac you need to create the AutofacWebApiDependencyResolver.

HttpConfiguration httpConfig = new HttpConfiguration();
var webApiResolver = new AutofacWebApiDependencyResolver(container);
httpConfig.DependencyResolver = webApiResolver;

And for using SignalR and Autofac you need to create the AutofacDependencyResolver

HubConfiguration hubConfig = new HubConfiguration();
var signalRResolver = new AutofacDependencyResolver(container);
hubConfig.Resolver = signalRResolver;

Error resolving

I followed the instructions of Autofac to create correct registrations for SignalR and WebApi. But when the application is started I got the following error:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'
on type 'HubContextProvider`1[IStateHubClient]' can be invoked with the available services and parameters:
Cannot resolve parameter 'Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager connectionManager'
of constructor 'Void .ctor(Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager)'.

Ok... so somehow I am missing the IConnectionManager, so who is responsible for creating/register this interface? 

Somehow this interface is created by the AutofacDependencyResolver from Autofac SignalR, but is not injected in the container that is used by the application. 

Register IConnectionManager

There seems to be a simple solution for the error. Just register the IConnectionManager at the container yourself. But.. Where can I get the IConnectionManager? In the HubConfiguration!

builder.RegisterInstance(hubConfig.Resolver.Resolve<IConnectionManager>());

So the registration looks like this:

HttpConfiguration httpConfig = new HttpConfiguration();
HubConfiguration hubConfig = new HubConfiguration();

var builder = new ContainerBuilder();

// Register all typed needed in the application
// ....
builder.RegisterInstance(hubConfig.Resolver.Resolve<IConnectionManager>());
builder.RegisterHubs(Assembly.GetExecutingAssembly());

var container = builder.Build();

var webApiResolver = new AutofacWebApiDependencyResolver(container);
httpConfig.DependencyResolver = webApiResolver;

var signalRResolver = new AutofacDependencyResolver(container);
hubConfig.Resolver = signalRResolver;

After adding the registration of the IConnectionManager everything seems to be working during startup. But the SignalR hubs and the handler are not using the same IConnectionManager. It seems like that the 'new AutofacDependencyResolver(..)' overrides the IConnectionManager implementation internally. So when the Hub's are created it uses the internal IConnectionManager and the HubHandlers are using the just registered IConnectionManager.

So now we need to have a solution for this.

Solution 1 [builder.Update(..)]

After using our big friend Google I found one solution which uses the ContainerBuilder.Update() method. First we need to register all our own registrations, then create the dependency resolvers and after the add the IConnectionManager to the current container.

HttpConfiguration httpConfig = new HttpConfiguration();
HubConfiguration hubConfig = new HubConfiguration();

var builder = new ContainerBuilder();

// Register all typed needed in the application
// ....
builder.RegisterHubs(Assembly.GetExecutingAssembly());

var container = builder.Build();

var webApiResolver = new AutofacWebApiDependencyResolver(container);
httpConfig.DependencyResolver = webApiResolver;

var signalRResolver = new AutofacDependencyResolver(container);
hubConfig.Resolver = signalRResolver;

var signalRBuilder = new ContainerBuilder();
signalRBuilder.RegisterInstance(hubConfig.Resolver.Resolve<IConnectionManager>());
signalRBuilder.Update(container);

Solution 2 [without builder.Update(...)]

However solution 1 seems to work it is best practice to not update the registrations after building the container. See Consider a container as immutable in the Autofac documentation.

This is also visible in Visual Studio with the warning:

Warning	CS0618	'ContainerBuilder.Update(IContainer)' is obsolete: 
'Containers should generally be considered immutable. Register all of your dependencies 
before building/resolving. If you need to change the contents of a container, you
technically should rebuild the container. This method may be removed in a future major release.

Mmm... we should fix this...before getting some major release of Autofac that does not support the update() method.

I've seen some complex solutions for registration of the IConnectionManager using different kind of complex methods. Like registration of the SignalR dependency resolver and using this resolver again for getting the connection manager. I also tried a solution for registration using lambda method.

builder.Register(context => hubConfig.Resolver.Resolve<IConnectionManager>());

Idea behind this was to be able to register the IConnectionManager but when the Resolve() occurs use the hubConfig to get the IConnectionManager. But this results in a StackOverflowException... Nice :(...

So now the solution that works for me and is not using the ContainerBuilder.Update() method is by changing the HubContextProvider from the beginning of the post to use the HubConfiguration instead of the IConnectionManager.

public class HubContextProvider<THubClient> : IHubContextProvider<THubClient>
    where THubClient : class
{
	private readonly IConnectionManager connectionManager;
	public HubContextProvider(HubConfiguration hubConfiguration)
	{
		this.connectionManager = hubConfiguration.Resolver.Resolve<IConnectionManager>();
	}

	public IHubContext<THubClient> GetHubContext<THub>()
		where THub : Hub<THubClient>
	{
		return this.connectionManager.GetHubContext<THub, THubClient>();
	}
}

For this to work, the HubConfiguration must be available in the container, but that one simple extra call:

HttpConfiguration httpConfig = new HttpConfiguration();
HubConfiguration hubConfig = new HubConfiguration();

var builder = new ContainerBuilder();

// Register all typed needed in the application
// ....
builder.RegisterHubs(Assembly.GetExecutingAssembly());
builder.RegisterInstance(hubConfig);

var container = builder.Build();

var webApiResolver = new AutofacWebApiDependencyResolver(container);
httpConfig.DependencyResolver = webApiResolver;

var signalRResolver = new AutofacDependencyResolver(container);
hubConfig.Resolver = signalRResolver;

There is no need for registering the IConnectionManager anymore.

Yes... No I have a solution that works with Owin, SignalR, WebApi and Autofac without using ContainerBuilder.Update().

Update:

I got some questions about the registration of the HubContextProvider<>. This is the registration I used:

builder.RegisterGeneric(typeof(HubContextProvider<>)).As(typeof(IHubContextProvider<>));

With this all the HubContextProviders are automatically added to the registration.