5
votes

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.

hub

[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);
    }
}

startup.cs

  var kernel = new StandardKernel();
  var resolver = new NinjectSignalRDependencyResolver(kernel);

  var config = new HubConfiguration()
  {
        Resolver = resolver,
  };

  app.MapSignalR(config);

NinjectSignalRDependencyResolver

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));
    }
}

JavaScript

<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?

1
Thanks for the linkl - but I'm already using the same Dependency Resolver and technique.Code Uniquely
How are you initializing/setting the resolver? Are you doing something like GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(kernel);?Rui Jarimba
I tried putting that before and after the line with app.MapSignalR(config); but it made no difference either timeCode Uniquely
@Code Uniquely, you need to create a binding for IUserService in the Start method in startup.cs. below link may help you: asp.net/signalr/overview/signalr-20/extensibility/…Lin

1 Answers

10
votes

The easiest way to achieve this is to get rid of the Custom Dependency resolver entirely and just use a very simple IHubActivator instead.

startup.cs

public void Configuration(IAppBuilder app)
{
    app.MapSignalR();
}

Hubactivator.cs

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);
    }
}

RegisterServices

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...