Reputation: 445
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
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
Reputation: 3716
You're very close. You just need:
public class MyHub : Hub
{
readonly IState _state;
public MyHub(IState state)
{
_state = state;
}
}
Upvotes: 0
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
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
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
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