Martin T.
Martin T.

Reputation: 445

How can I set up SignalR Hub Dependency Injection in ASP.NET 5 (vNext)?

Trying to do dependency injection into my SignalR Hub class using the SignalR-Server which is part of ASP.NET 5 (repo). I tried to figure this out from the tutorial at this link but I can't seem to identify how I can do this given that GlobalHost is no longer available. Here's what I'm trying to do:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
    services.AddSingleton<IState, State>();
}

public void Configure(IApplicationBuilder app)
{
    app.UseSignalR();
}

MyHub.cs

public class MyHub : Hub
{
    public IState State { get; set; }

    // SignalR accepts this parameterless ctor
    public MyHub()
    {
    }

    // SignalR won't use this because it has a parameter
    public MyHub(IState state)
    {
        State = state;
    }
}

How can I get SignalR-Server to use the MyHub(IState state) constructor injecting the required dependencies?

Upvotes: 11

Views: 24121

Answers (6)

sebu
sebu

Reputation: 2954

In .NET 5 you can directly resolve the IServiceProvider and later you can have the required service. Please check the below codes:

public class MyHub : Hub
{
    public IState State { get; set; }
    private readonly IServiceProvider _serviceProvider;
    public MyHub(IServiceProvider serviceProvider)
    {
        _serviceProvider=serviceProvider;
        State = _serviceProvider.GetRequiredService<IState>();
    }

    public override Task OnConnected()
    {
        State.Clients = Clients;
        State.Groups = Groups;
        return base.OnConnected();
    }
}

Upvotes: 0

Sith2021
Sith2021

Reputation: 3716

You're very close. You just need:

public class MyHub : Hub
{
    readonly IState _state;

    public MyHub(IState state)
    {
        _state = state;
    }
}

Upvotes: 0

Stalso
Stalso

Reputation: 1484

I have simply made constructor with dependencies. For example, I need my IUnitOfWork instance (which was configured in startup) in hub. That is working code

[HubName("receipts")]
public class ReceiptsHub : Hub
{
    public IUnitOfWork<string> UnitOfWork { get; set; }

    public ReceiptsHub(IUnitOfWork<string> unitOfWork) : base()
    {
        UnitOfWork = unitOfWork;
    }

    public override Task OnConnected()
    {
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        return base.OnDisconnected(stopCalled);
    }
}

Upvotes: 0

Allan Clempe
Allan Clempe

Reputation: 156

the best way (for Asp.Net 5) create a custom resolver to DefaultDependencyResolver that receives IServiceProvider:

 public class CustomSignalRDependencyResolver : DefaultDependencyResolver
{
    private readonly IServiceProvider _serviceProvider;

    public CustomSignalRDependencyResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public override object GetService(Type serviceType)
    {
        var service = _serviceProvider.GetService(serviceType);

        return service ?? base.GetService(serviceType);
    }


}

Then on StartUp class

 public void ConfigureServices(IServiceCollection services)
    {

         services.AddSingleton<IState, State>();

        //... other services


        GlobalHost.DependencyResolver = new CustomSignalRDependencyResolver(services.BuildServiceProvider());

    }

Upvotes: 3

Martin T.
Martin T.

Reputation: 445

I managed to resolve this by adding my State class as a Singleton for IState in Startup.ConfigureServices, and then making a ServiceProvider property publicly available on my Startup.cs class. From there, I was able to GetRequiredService within the constructor of my SignalR Hub class. It isn't the ideal solution and hopefully I'll be able to adjust this to use constructor/property injection as the platform reaches RC.

Here's my code:

Startup.cs

public static IServiceProvider __serviceProvider;

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
    services.AddSingleton<IState, State>();
    __serviceProvider = services.BuildServiceProvider();
}

public void Configure(IApplicationBuilder app)
{
    app.UseSignalR();
}

MyHub.cs

public class MyHub : Hub
{
    public IState State { get; set; }

    public MyHub()
    {
        State = (IState) Startup.__serviceProvider.GetRequiredService(typeof (IState));
    }

    public override Task OnConnected()
    {
        State.Clients = Clients;
        State.Groups = Groups;
        return base.OnConnected();
    }
}

In this way, I was able to set properties and call methods on IState implementing objects from within MyHub, allowing me to persist my app state in memory.

Upvotes: 2

radu-matei
radu-matei

Reputation: 3520

Ok. Now, I used Autofac, which I am not sure it has ASP.NET 5 integration yet. But if(for now) only target .NET 4.6, you should be fine.

I just published this repository which contains a basic project setup with SignalR and Autofac for dependency injection.

Now, I did the dependency injection setup in order to achieve the following:

  • be able to inject dependencies into my hub

  • be able to get the context for my hubs in order to send to clients from outside the hub without using GlobalHost (which is no longer available in .NET 5, but also shouldn't be used since it's a static global object)

I hope you manage to setup your project (even though I don't think you will be able to keep DNX in your build options since Autofac doesn't have the library .NET 5 ready yet.

I hope this helps! Best of luck!

https://github.com/radu-matei/SignalRDependencyInjection

EDIT: If you want to use NInject (and build your own dependency resolver if you want to target DNX, you can follow this repository from the official guys from SignalR (actually from the guy who wrote SignalR):

https://github.com/DamianEdwards/NDCLondon2013/tree/master/DependencyInjection

In this demo they use NInject to create their own dependency resolver, so you shouldn't have any problems targeting DNX if you have NInject libraries.

UPDATE: After reading a little about Dependency Injection in ASP.NET 5, it seems that it is done in an unified manner. If you haven't had a look at this article, I recommend it, even though it doesn't specifically show SignalR DI.

Upvotes: 0

Related Questions