SignalR-Dependency Injection
This is a fourth contribution in a series dedicated to SignalR. The previous post focused on publishing data from .net services using hub proxies.
Setting up dependency injection with SignalR is pretty straightforward. SignalR uses DefaultDependencyResolver to resolve its own services (IConnectionManager, IConfigurationManager, IJsonSerializer, ITransportManager and many more) and hub extensions (IHubManager, IJavaScriptProxyGenerator and many more). Using GlobalHost, you can set your own dependency resolver.
Extending the DefaultDependencyResolver
When it comes to writing your own dependency resolver for SignalR, you have two options:
- You can implement IDependencyResolver and write the entire logic yourself (for the brave with lots of time)
- You can extend the DefaultDependencyResolver and override members with your own logic (the suggested route)
The DefaultDependencyResolver Members
1public virtual object GetService(Type serviceType);
2public virtual IEnumerable<object> GetServices(Type serviceType);
3public virtual void Register(Type serviceType, Func<object> activator);
4public virtual void Register(Type serviceType, IEnumerable<Func<object>> activators);
All you need to do when extending the DefaultDependencyResolver is to override the GetService and GetServices methods. In the example below, I’m using Castle.Windsor container, but similar pattern can be used with any other DI containers. You can find few existing implementations below.
1public class SignalrDependencyResolver : DefaultDependencyResolver
2{
3 private readonly IKernel _kernel;
4
5 public SignalrDependencyResolver(IKernel kernel)
6 {
7 _kernel = kernel;
8 }
9
10 public override object GetService(System.Type serviceType)
11 {
12 //check if component exists in your container, if not use base to resolve
13 return _kernel.HasComponent(serviceType) ? _kernel.Resolve(serviceType) : base.GetService(serviceType);
14 }
15
16 public override IEnumerable<object> GetServices(Type serviceType)
17 {
18 var objects = _kernel.HasComponent(serviceType) ? _kernel.ResolveAll(serviceType).Cast<object>() : new object[] { };
19 return objects.Concat(base.GetServices(serviceType));
20 }
21}
In order to wire up your custom DependencyResolver, you need to set the DependencyResolver via GlobalHost.
1protected void Application_Start()
2{
3 var container = CreateContainer();
4 //container init code ...
5
6 //create dependency resolver
7 var signalrDependency = new SignalrDependencyResolver(container.Kernel);
8 GlobalHost.DependencyResolver = signalrDependency;
9 RouteTable.Routes.MapHubs(signalrDependency);
10
11 //further startup code
12 //...
13}
With the setup above, you can register all your hubs in your container.
1public class HubsInstaller : IWindsorInstaller
2{
3 public void Install(IWindsorContainer container, IConfigurationStore store)
4 {
5 container.Register(
6 AllTypes.FromAssembly(typeof(MvcApplication).Assembly)
7 .BasedOn<Hub>().Configure(
8 x => x.Named(x.Implementation.FullName.ToLower()).LifeStyle.Transient));
9 }
10}
Your container will then auto-resolve any services that are already registered.
1public class ChatHub : Hub
2{
3 private readonly IRepository _repository;
4
5 public ChatHub(IRepository repository)
6 {
7 _repository = repository;
8 }
9
10 //methods ...
11}
Under The Hood Of DefaultDependecyResolver
You can check out the default dependency resolver at GitHub. You can find all the services that are registered – the resolver keeps then in a private readonly dictionary Dictionary<Type, IList<Func». If you fancy replacing an internal part of SignalR with your own implementation, you can locate the correct interface and register your own implementation in your container. The custom dependency resolver will then resolve your implementation.
Existing SignalR Dependency Injection Projects
SignalR Unity SignalR Ninject SignalR Autofac
Related Articles
SignalR – Introduction To SignalR SignalR – Publish Data Using IHubContext SignalR – Publish Data Using Proxies SignalR – Dependency Injection
Any questions or comments, give me a shout @mirajavora