13

Is there a good way to call methods in SignalR hub from a controller ?

Right now I have this:

public class StatsHub : Hub
{
    private static readonly Lazy<StatsHub> instance = new Lazy<StatsHub>(() => new StatsHub());
    public static StatsHub Instance { get { return instance.Value; } }

    public StatsHub()
    {
        if (this.Clients == null)
        {
            var hubContext = SignalR.GlobalHost.ConnectionManager.GetHubContext<StatsHub>();
            this.Clients = hubContext.Clients;
            this.Groups = hubContext.Groups;
        }
    }

    // methods here...
}

so in my controller actions I can just say, for example

StatsHub.Instance.SendMessage("blah");

and it's almost good, except that hubContext doesn't have Caller or Context properties of Hub - which are nice to have.

Hopefully, there's a better way to do this ?

Evgeni
  • 3,341
  • 7
  • 37
  • 64

3 Answers3

18

If you want to broadcast over a hub from outside of the hub, you need GlobalHost.ConnectionManager.GetHubContext<MyHub>() to get ahold of the hub context. You can then use this context to broadcast via the .Clients property.

As indicated in your sample code you already get ahold of the hub context, but doing so inside the hub just doesn't feel right in my opinion. If you're only using the logic in SendMessage() from your controller actions, I'd move the code right into the controller action and use the hub context obtained via GetHubContext<T>() from there.

Please note that the Caller or Context property will always be null in this scenario, because SignalR wasn't involved when making a request to the server and therefore cannot provide the properties.

Alexander Köplinger
  • 2,497
  • 17
  • 15
16

Found a DefaultHubManager, which is what I need, I think.

DefaultHubManager hd = new DefaultHubManager(GlobalHost.DependencyResolver);
var hub = hd.ResolveHub("AdminHub") as AdminHub;
hub.SendMessage("woohoo");

Works. If there's an even better/preferred way - please share.

Evgeni
  • 3,341
  • 7
  • 37
  • 64
  • 5
    This works no more (in SignalR 2?). See http://stackoverflow.com/questions/17896739/use-hub-methods-from-controller . – Jouni Heikniemi Feb 27 '14 at 14:07
  • `DefaultHubManager` exists in SignalR 2.x however `hub.Context` is null, so all operations fail. – Dai Nov 02 '16 at 06:39
  • this works in signalR 2.0 but i get an exception Using a Hub instance not created by the HubPipeline is unsupported – GreyCloud Jun 08 '17 at 13:39
1

As per the latest documentation, IHubContext can be injected by dependency injection.

documentation : https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0

In service you could do

public class NotificationService : INotificationService
{
    private readonly IHubContext<NotificationHub> _hubContext;

    public NotificationService(IHubContext<NotificationHub> hubContext)
    {
        _hubContext = hubContext;
    }
}

In controller

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

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

Once you have HubContext you could send message to group/client etc.

public async Task SendMessage()
{
    return await _hubContext.Clients.All.SendAsync("Notify", $"Hello world");
}
Arjun Vachhani
  • 1,761
  • 3
  • 21
  • 44