On a project I’ve been working on I’ve been having some issues with combining these technologies. We already had an MVC application running using Ninject to wire everything together.
The Ninject MVC package, which you can install via NuGet, uses WebActivator to initialize the kernel. WebActivator enables you to wire up different packages without the need of putting everything in your Global.asax, it’s also more powerfull compared to the default PreApplicationStartMethod attribute which WebActivator actually leverages so you can have multiple startup methods in your assembly.
In SignalR I needed my own ConnectionIdGenerator. The framework has been build to allow an IoC container to manage dependencies so it was trivial to add my custom class. I just added one line to my RegisterServices method in the NinjectMVC3 class which is added in the App_Start folder when you add the Ninject MVC package. By default this code is wired up by the PreApplicationStartMethod of WebActivator.
private static IKernel CreateKernel() { //more wire up stuff kernel.Bind<IConnectionIdGenerator>().To<MyConnectionFactory>(); GlobalHost.DependencyResolver = new SignalR.Ninject.NinjectDependencyResolver(kernel); } |
Everything was looking good and it worked.
Sometimes.
Occasionally I could see that my own ConnectionIdGenerator was being used and sometimes the default ConnectionIdGenerator that ships with SignalR was still active. I could not really find usefull information on the web and moved code around from WebActivator to the Global.asax file and back again. Even changing the order of steps that were executed to see if that had any effect, but nothing really worked.
I went back to the Signlar Wiki and reread the page on extensibility and especially the part about changing the DependencyResolver.
It clearly states that you need to configure SignalR first and ASP.NET MVC later. A bit more down on the page it’s stated that when you want to use another DependencyResolver and if you are using WebActivator, you need to wire it up in the PostApplicationStart.
Clearly there were more moving pieces than I had thought.
So, working with this new insight, I removed all MVC configuration code that was in the Global.asax file, where it happens by default when you create a new project, and moved it to a method which I decorated with the PostApplicationStartAttribute.
[assembly: WebActivator.PostApplicationStartMethod(typeof(MyNamespace.App_Start.NinjectMVC3), "PostStart")] public static void PostStart() { GlobalHost.DependencyResolver = new SignalR.Ninject.NinjectDependencyResolver(bootstrapper.Kernel); RouteTable.Routes.MapHubs(); AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } |
Running the application again clearly showed everything was in the right place now. SignalR was now properly configured to use my own Ninject kernel. The kernel itself is still being constructed and configured in the PreApplicationStart phase, SignalR and MVC are configured in the PostApplicationStart phase.