Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR + Autofac + OWIN: Why doesn't GlobalHost.ConnectionManager.GetHubContext work?

I'm trying to use OWIN, SignalR and Autofac in a single project.

I'm setting things up with regards to signalR as follows:

       // Create the AutoFac container builder:         var builder = new ContainerBuilder();          // ...[Register various other things in here]...          // register signalR Hubs         builder.RegisterHubs(Assembly.GetExecutingAssembly());          // Build the container:         var container = builder.Build();          // Configure SignalR with the dependency resolver.         app.MapSignalR(new HubConfiguration         {             Resolver =  new AutofacDependencyResolver(container)         }); 

My issue is that when I use the Autofac SignalR integration, I can no longer get a signalR Hub Context on the server (in a webapi controller for example) and so can't send messages from server side to the connected clients. Something like the following is how I do this when I'm not using the Autofac signalR integration:

var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>(); hubContext.Clients.All.notification("Test Message"); 

But this doesn't work when I add Autofac into the mix - I don't get any error message and I do seem to get a hubContext, but calls on it don't actually seem to get to the clients.

If I comment out the use of the dependency resolver for signalR in the call to MapSignalR, the call to GetHubContext works again and messages reach the signalR clients sucessfully, but of course I can no longer use IoC on my hubs. e.g.

        // Configure SignalR with the dependency resolver.         app.MapSignalR(new HubConfiguration         {             // Resolver =  new AutofacDependencyResolver(container)         }); 

Can anybody tell me why using the AutofacDependencyResolver stops GlobalHost.ConnectionManager.GetHubContext from working correctly??

NOTE: One other thing I have tried is instead of using GlobalHost.ConnectionManager.GetHubContext() I tried injecting an IConnectionManager into the webapi controller from which I want to send a message to clients, then calling GetHubContext on that, but Autofac couldn't resolve the IConnectionManager.

I did find the following article by Piotr Szmyd which apparently allows this:

http://www.szmyd.com.pl/blog/wiring-signalr-with-autofac

but this appears to be based on obsolete signalR builds, and while there seems to be a nuget package for it here:

http://www.nuget.org/packages/SignalR.AutoFac/

it also seems well out of date.

like image 430
mutex Avatar asked Jan 15 '14 00:01

mutex


2 Answers

If you use a custom dependency resolver with SignalR, you can no longer use GlobalHost unless you modify it:

GlobalHost.DependencyResolver = new AutofacDependencyResolver(container); IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();  // A custom HubConfiguration is now unnecessary, since MapSignalR will // use the resolver from GlobalHost by default. app.MapSignalR(); 

If you don't want to modify GlobalHost, you will have to manually resolve your IConnectionManager:

IDependencyResolver resolver = new AutofacDependencyResolver(container); IHubContext hubContext = resolver.Resolve<IConnectionManager>().GetHubContext<MyHub>();  app.MapSignalR(new HubConfiguration {     Resolver = resolver }); 
like image 95
halter73 Avatar answered Sep 22 '22 13:09

halter73


For a complete answer, with SignalR, Autofac, and OWIN, I did the following:

// register IPersistantConnectionContext for access to SignalR connection // and IDependencyResolver to enable inection of the container into its // construction for the config object. var builder = new ContainerBuilder(); builder.RegisterType<Autofac.Integration.SignalR.AutofacDependencyResolver>()     .As<IDependencyResolver>()     .SingleInstance(); builder.Register((context, p) =>         context.Resolve<IDependencyResolver>()             .Resolve<Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager>()             .GetConnectionContext<SignalRConnection>());  // ... other registrations  var container = builder.Build();  var signalrConfiguration = new ConnectionConfiguration {     Resolver = container.Resolve<IDependencyResolver>(), };  app.UseAutofacMiddleware(container);  app.MapSignalR<SignalRConnection>("/signalr", signalrConfiguration);  // ... other middleware 

In my controllers, I included a parameter of the type IPersistentConnectionContext and the correct instance is injected.

I was using a PersistentConnection, but it should be similar for Hubs.

like image 32
Nathan Avatar answered Sep 20 '22 13:09

Nathan