Search code examples
c#signalrasp.net-core-2.0asp.net-core-signalr

Call SignalR Core Hub method from Controller


How can I call SignalR Core Hub method from Controller?
I am using ASP.NET Core 2.0 with Microsoft.AspNetCore.SignalR (1.0.0-alpha2-final).

I have windows service which communicate with Excel, SolidEdge ... When operation is complete it post request to my controller in ASP.NET Core application. Now I need to inform all clients connected to server with SignalR that external program completed some task.
I can not change the way window service works. (Can not connect to SignalR from window service).
I found plenty solution for old SignalR (GlobalHost.ConnectionManager.GetHubContext), but much has changed and those solutions are not working anymore.

My controller:

[Route("API/vardesigncomm")]
public class VarDesignCommController : Controller
{
    [HttpPut("ProcessVarDesignCommResponse/{id}")]
    public async Task<IActionResult> ProcessVarDesignCommResponse(int id)
    {
        //call method TaskCompleted in Hub !!!! How?

        return new JsonResult(true);
    }
}

My hub:

public class VarDesignHub : Hub
{
    public async Task TaskCompleted(int id)
    {
        await Clients.All.InvokeAsync("Completed", id);
    }
}

Solution

  • Solution 1

    Another possibility is to inject your HubContext into your controller like:

    public VarDesignCommController(IHubContext<VarDesignHub> hubcontext)
    {
        HubContext = hubcontext;
        ...
    }
    
    private IHubContext<VarDesignHub> HubContext
    { get; set; }
    

    Then you can also call

    await this.HubContext.Clients.All.InvokeAsync("Completed", id);
    

    But then you will direct call methods on all clients.

    Solution 2

    You can also work with typed hubs: Simple create an interface where you define which methods your server can call on the clients:

    public interface ITypedHubClient
    {
        Task BroadcastMessage(string name, string message);
    }
    

    Inherit from Hub:

    public class ChatHub : Hub<ITypedHubClient>
    {
        public void Send(string name, string message)
        {
            Clients.All.BroadcastMessage(name, message);
        }
    }
    

    Inject your the typed hubcontext into your controller, and work with it:

    [Route("api/demo")]
    public class DemoController : Controller
    {
        IHubContext<ChatHub, ITypedHubClient> _chatHubContext;
        public DemoController(IHubContext<ChatHub, ITypedHubClient> chatHubContext)
        {
            _chatHubContext = chatHubContext;
        }
    
        // GET: api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            _chatHubContext.Clients.All.BroadcastMessage("test", "test");
            return new string[] { "value1", "value2" };
        }
    }