I have the following simple Hub Class to list users using a injected User Service. A startup class that uses the NinjectSignalRDependencyResolver. And very simple client script.
[HubName("dashboardHub")]
public class DashboardHub : Hub
{
private readonly IUserService _users;
public DashboardHub(IUserService users)
{
_users = users;
}
public void Initialize()
{
var users = _users.ListUsers();
Clients.All.UpdateStatus(users);
}
}
var kernel = new StandardKernel();
var resolver = new NinjectSignalRDependencyResolver(kernel);
var config = new HubConfiguration()
{
Resolver = resolver,
};
app.MapSignalR(config);
public class NinjectSignalRDependencyResolver : DefaultDependencyResolver
{
private readonly IKernel _kernel;
public NinjectSignalRDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public override object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType).Concat(base.GetServices(serviceType));
}
}
<script>
$(function () {
var dashboard = $.connection.dashboardHub;
dashboard.client.updateStatus = function (users) {
var elem= $('.userList');
elem.html('');
$.each(users, function (i, user) {
parent.append("<p>" user.Name + "<p>");
});
};
$.connection.hub.start().done(function () {
dashboard.server.initialize();
});
});
</script>
I register the Interface with Ninject in the stadard way inside RegisterServices
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserService >().To<UserService>().InSingletonScope();
...
}
When open client with the script. The code runs and there are no exceptions or script errors generated. The Constructor of Dashboard is never called and neither is the Initialize() method - even though the object exists in the JavaScript and so does the method. The the user list is never populated as client.updateStatus is never called.
If I add a default constructor to the Hub class then this is called and so too is the Initialize method - but it obviously now falls over as the private IUserService variable is null.
public DashboardHub()
{
}
How do you configure SignalR 2.0 and Ninject to allow Hubs to have dependency Injected constructor arguments?
The easiest way to achieve this is to get rid of the Custom Dependency resolver entirely and just use a very simple IHubActivator instead.
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
public class HubActivator : IHubActivator
{
private readonly IKernel container;
public HubActivator(IKernel container)
{
this.container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return (IHub)container.GetInstance(descriptor.HubType);
}
}
private static void RegisterServices(IKernel kernel)
{
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new HubActivator(kernel));
kernel.Bind<IUserService >().To<UserService>().InSingletonScope();
...
}
Simple as that - everything works and Interfaces are injected into the constructors as you would expect...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With