52

I'm trying to get the context for a hub using the following:

var hubContext = GlobalHost.ConnectionManager.GetHubContext<SomeHub>();

The problem is that GlobalHost is not defined. I see it is part of the SignalR.Core dll. At the moment, I have the following in my project .json file, under dependencies:

"Microsoft.AspNet.SignalR.Server": "3.0.0-*"

If I add the latest available version of Core:

"Microsoft.AspNet.SignalR.Server": "3.0.0-*",
"Microsoft.AspNet.SignalR.Core" :  "2.1.2"

I get a whole bunch of errors because server and core are conflicting. If I change them to both use version "3.0.0-*", all the conflicts go away, but GlobalHost cannot be found. If I remove Server, and just user Core version 2.1.2 then GlobalHost works, but all the other things needing Server, obviously do not.

Any ideas?

Søren
  • 6,517
  • 6
  • 43
  • 47
  • Current solution provided in [this answer](http://stackoverflow.com/a/38832879/957950) to a similar question. – brichins Mar 08 '17 at 22:35

6 Answers6

105

IConnectionManager does not exist any more in SignalR for ASP.Net Core.
I've been using HubContext for getting access to a hub.

public class HomeController : Controller
{
    private readonly IHubContext<LiveHub> _hubContext;

    public HomeController(IHubContext<LiveHub> hubContext)
    {
        _hubContext = hubContext;
    }

    public void SendToAll(string message)
    {
        _hubContext.Clients.All.InvokeAsync("Send", message);
    }
}

I'm using .net core 2.0.0 and SignalR 1.0.0-alpha1-final

BozoJoe
  • 6,117
  • 4
  • 44
  • 66
Søren
  • 6,517
  • 6
  • 43
  • 47
  • Hi! Can you please post an example of how do you register HubContext class in IoC container? – Andrew Nikolin Sep 27 '17 at 20:45
  • 7
    @AndrewNikolin, not need to register `HubContext`. just introduce your Hub in `Configure` method. `app.UseSignalR(routes => { routes.MapHub("live"); });` l think by `services.AddSignalR();` the HubContext would be registered automatically ... – Søren Sep 28 '17 at 14:05
  • 1
    Thanks, that helped a lot. But how would I access the `HubContext` from outside a controller? Is there a way to call a hub method also from a static context? – lenniep Oct 16 '17 at 14:35
  • 2
    @lenniep `HubContext` is reachable wherever `IServiceProvider` is available. you could get [access](https://github.com/aspnet/DependencyInjection/issues/294#issuecomment-142206554) to `IServiceProvider` in static class by some tip and tricks but it's not recommended at all. – Søren Oct 17 '17 at 06:04
  • @Soren makes sense, thanks a lot. I will avoid this since I agree it's rather bad design. This has helped me as well: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ – lenniep Oct 17 '17 at 06:44
  • for me, connections is coming empty with this code snippet. Any help!! – santu47 Dec 27 '18 at 07:22
  • i was thinking as if i have to actually implement the `IHubContext` and then inject that using DI but then i realized i'd have to implement `Clients` and `Groups` etc, but reading the comments i realized that `services.AddSignalR();` actually injects `IHubContext`by default so it saved me alot of frustration! documentation isn't clear on this to my knowledge. thanks to @Soren ! – Niklas May 10 '19 at 17:43
  • @Soren that works unless the Hub has other dependencies, i.e. on MyApi. – William Jockusch Feb 13 '20 at 15:40
  • 1
    for .net 5 await _hubContext.Clients.All.SendAsync("yourmethod", yourparameters); – user2475096 May 01 '21 at 05:46
25

Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager is a DI injected service through which you can get the hub context...For example:

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure;
using Microsoft.AspNet.Mvc;

public class TestController : Controller
{
     private IHubContext testHub;

     public TestController(IConnectionManager connectionManager)
     {
         testHub = connectionManager.GetHubContext<TestHub>();
     }
 .....
Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
Kiran
  • 56,921
  • 15
  • 176
  • 161
9

To use the hub in a backgroud service, in addition to controllers, you must use the IHostedService interface and get the hub by DI.

public class MyBackgroundService : IHostedService, IDisposable
{
    public static IHubContext<NotifierHub> HubContext;

    public MyBackgroundService(IHubContext<NotifierHub> hubContext)
    {
        HubContext = hubContext;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        //TODO: your start logic, some timers, singletons, etc
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        //TODO: your stop logic
        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

Then you can call your hub from anywhere in your code from HubContext static field:

MyBackgroundService.HubContext.Clients.All.SendAsync("UpdateData", myData).Wait();

Learn more about IHostedService: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1

You can create and start a timer in MyBackgroundService and call the hub in ElapsedEvent.

Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
RenanStr
  • 1,208
  • 1
  • 13
  • 15
  • Thank you so much. This was exactly what I needed to do to get SignalR working from background (hangfire) jobs – Aaron Nov 15 '19 at 23:16
2

I needed to be able to access the Hub Context from outside the app request thread - because I was subscribing to NServicebus messages, and needed to be able to trigger a client function when I received a message.

Here's how I got it sorted:

public static IServiceProvider __serviceProvider;

then during startup configuration

app.UseServices(services =>
        {
            __serviceProvider = new ServiceCollection()
            .BuildServiceProvider(CallContextServiceLocator.Locator.ServiceProvider);
        });

Then anywhere else in the vNext asp.net application (any other thread)

 var manager = Startup.__serviceProvider.GetRequiredService<IConnectionManager>();
            var hub = manager.GetHubContext<ChatHub>();

Hope this helps!

Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
nimo
  • 499
  • 4
  • 6
2

I added some code to my Startup.cs to grab reference to the ConnectionManager which you can then use to do a GetHubContext at anytime from anywhere in your code. Similar to Nimo's answer but a little different, maybe simpler.

services.AddSignalR(options =>
{
    options.Hubs.EnableDetailedErrors = true;
});

var provider = services.BuildServiceProvider();

//Hold on to the reference to the connectionManager
var connManager = provider.GetService(typeof(IConnectionManager)) as IConnectionManager;

//Use it somewhere else
var hub = connManager.GetHubContext<SignalHub>();
Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
Matt Watson
  • 980
  • 7
  • 10
  • How can you find the connManager somewhere else? Don't you have to inject or refrence it somehow since its not static? – stibay Jul 19 '16 at 10:53
  • 5
    As of the latest build, 0.0.2-alpha1-21709, this technique no longer works. I create a static variable for IConnectionManager in the startup class. When it is referenced in another class, the IHubContext is available but hub.Clients.All.SendMessage("foo") does not send a message to the clients. – Bill Shihara Jul 28 '16 at 07:25
  • @BillShihara - did you resolve the problem you mentioned here? – Glen Little Apr 03 '18 at 04:42
1

I'm looking at SignalR source code and it seems that IHubContext is registered as a singleton.

Which means you get the same instance whenever you access it.

Which means you can simply save it in a static var and use it from whatever.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHubContext<MyHub> hubContext)
{
    _staticVar = hubContext;
}

But be warned - it's an anti-pattern.

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
  • I also wanted to use it within NServiceBus handler. End up following what @RenanStr suggested. works like a charm. But when you think about it, it's not something different to what you suggested "Static HubContext". – Dharmesh Tailor May 05 '22 at 23:00