7
votes

Is it possible to use dependency injection to inject dependencies into SignalR on ASP.NET Core v2.0?

Assuming the following hub and dependency:

public MyHub : Hub {

    private readonly IMyDependency dependency;

    public MyHub(IMyDependency dependency) {
        this.dependency = dependency;
    }
}

public void MyDependency : IDependency
{
    public void MyMethod() {
        Console.WriteLine("I'm a dependency!");
    }
}

I've scoured a bit of the web and there isn't anything obvious out there. I found this tutorial which at first seemed quite promising until I realised it was for Microsoft.AspNetCore.SignalR.Server which didn't ship in the end.

At the moment I have the following setup using Autofac and it's not working:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSignalR();

        // Configue Autofac
        var containerBuilder = new ContainerBuilder();

        containerBuilder.RegisterModule<MyModule>();

        // Configure SignalR hubs for dependency injection
containerBuilder.RegisterSignalRHubs(typeof(Startup).GetTypeInfo().Assembly);

        containerBuilder.Populate(services);
        var container = containerBuilder.Build();
        return new AutofacServiceProvider(container);
    }
}

public static class AutoFacExtensions
{
    public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterSignalRHubs(this ContainerBuilder builder, params Assembly[] assemblies)
    {
        return builder.RegisterAssemblyTypes(assemblies)
            .Where(t => typeof(IHub).IsAssignableFrom(t))
            .ExternallyOwned();
    }
}

public class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MyDependency>().As<IMyDependency>();
    }
}

It looks like the IHub interface doesn't exist anymore. I tried IHubContext<MyHub> in the hope that this might work with the latest version but sadly not.

When I have dependencies in my hub's constructor, the hub isn't created despite all of the dependencies registered with Autofac.

How can I achieve this with the lastest version 1.0.0.0-alpha2-final?

1
As much as it pains me to admit this, I was simply missing a registration for some of my dependencies - this is working with Hub instead of IHub. I was able to find out they weren't registered by assigning my IDependency to a Controller constructor instead of the Hub and then the error was obvious. This is indeed a way that can be used to use DI with SignalR (the current version at time of writing).Luke

1 Answers

7
votes

The example given in the question does work with version 1.0.0.0-alpha2-final of Microsoft.AspNetCore.SignalR with one slight tweak, use Hub rather than the now non-existent IHub.

public static class AutoFacExtensions
{
    public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterSignalRHubs(this ContainerBuilder builder, params Assembly[] assemblies)
    {
        // typeof(Hub), not typeof(IHub)
        return builder.RegisterAssemblyTypes(assemblies)
            .Where(t => typeof(Hub).IsAssignableFrom(t))
            .ExternallyOwned();
    }
}

Ensure that all of your dependencies are satisfied by assigning them to a controller. I'm not sure at this point how to troubleshoot broken dependencies when injecting into a SignalR hub with this method.