Redigera

Dela via


Send messages from outside a hub

The SignalR hub is the core abstraction for sending messages to clients connected to the SignalR server. It's also possible to send messages from other places in your app using the IHubContext service. This article explains how to access a SignalR IHubContext to send notifications to clients from outside a hub.

Note

The IHubContext is for sending notifications to clients, it is not used to call methods on the Hub.

View or download sample code (how to download)

Get an instance of IHubContext

In ASP.NET Core SignalR, you can access an instance of IHubContext via dependency injection. You can inject an instance of IHubContext into a controller, middleware, or other DI service. Use the instance to send messages to clients.

Inject an instance of IHubContext in a controller

You can inject an instance of IHubContext into a controller by adding it to your constructor:

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

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

With access to an instance of IHubContext, call client methods as if you were in the hub itself:

public async Task<IActionResult> Index()
{
    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}");
    return View();
}

Get an instance of IHubContext in middleware

Access the IHubContext within the middleware pipeline like so:

app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    //...
    
    if (next != null)
    {
        await next.Invoke();
    }
});

Note

When client methods are called from outside of the Hub class, there's no caller associated with the invocation. Therefore, there's no access to the ConnectionId, Caller, and Others properties.

Apps that need to map a user to the connection ID and persist that mapping can do one of the following:

  • Persist mapping of single or multiple connections as groups. See Groups in SignalR for more information.
  • Retain connection and user information through a singleton service. See Inject services into a hub for more information. The singleton service can use any storage method, such as:
  • Pass the connection ID between clients.

Get an instance of IHubContext from IHost

Accessing an IHubContext from the web host is useful for integrating with areas outside of ASP.NET Core, for example, using third-party dependency injection frameworks:

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder => {
                    webBuilder.UseStartup<Startup>();
                });
    }

Inject a strongly-typed HubContext

To inject a strongly-typed HubContext, ensure your Hub inherits from Hub<T>. Inject it using the IHubContext<THub, T> interface rather than IHubContext<THub>.

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string user, string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(user, message);
    }
}

See Strongly typed hubs for more information.

Use IHubContext in generic code

An injected IHubContext<THub> instance can be cast to IHubContext without a generic Hub type specified.

class MyHub : Hub
{ }

class MyOtherHub : Hub
{ }

app.Use(async (context, next) =>
{
    var myHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyHub>>();
    var myOtherHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyOtherHub>>();
    await CommonHubContextMethod((IHubContext)myHubContext);
    await CommonHubContextMethod((IHubContext)myOtherHubContext);

    await next.Invoke();
}

async Task CommonHubContextMethod(IHubContext context)
{
    await context.Clients.All.SendAsync("clientMethod", new Args());
}

This is useful when:

  • Writing libraries that don't have a reference to the specific Hub type the app is using.
  • Writing code that is generic and can apply to multiple different Hub implementations

Additional resources