Search code examples
c#asp.net-core-mvcsignalrsignalr-hubasp.net-core-signalr

Call Signalr method from Controller .Net Core 2.1


I am trying to call a method in the signalr Hub class from an (ASP.NET Core) MVC Controller, but I cannot find an example online that shows how to.

Note: There are lots of examples using older versions of signalr with the .Net Framework, but none that I can see that show how to do this in .Net Core.

I need to pass an id from the an MVC Action Result directly through to my Hub, without passing the id to the page, and then having to get a client connection back through to the hub.

public class ChatHub : Hub
{ 
    public async Task DoSomething(int id)
    {            
        //// Something in here.
    }
}



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

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

    public async Task<ActionResult> Index(int id) 
    {

         //// Call the DoSomething method from here, passing the id across.
         await _hubContext.Clients.All.SendAsync("AddToGroup", groupId);
    }
}

Is there a way to do this please? (Or am I looking at this the wrong way, and is there a better way to achieve the same result?)

Update: If I pass the Id into the view, and then use JavaScript to call the Hub, this then calls the DoSomething method, so I can see it all hangs together correctly, but not when I try to call it in C#.


Solution

  • I think you're misunderstanding how it all works together (which is the same thing I did up until yesterday), the hub code is for the client-side script code to call back into and then action, whereas the IHubContext is used as the strongly typed methods that will be sent to the Client-side

    Hub

    // This class is used by the JavaScript Client to call into the .net core application.
    public class ChatHub : Hub<IChatClient>
    {
    
        public static ConcurrentDictionary<string, string> Connections = new ConcurrentDictionary<string, string>();
    
        // As an example, On connection save the user name with a link to the client Id for later user callback
        public override Task OnConnectedAsync()
        {
            var user = Context.User.Identity.Name;
    
            Connections.AddOrUpdate(this.Context.ConnectionId, user, (key, oldValue) => user);
    
            return base.OnConnectedAsync();
        }
    
        public override Task OnDisconnectedAsync(Exception exception)
        {
            // Do something on disconnect.
        }
    
        // Add other methods you want to be able to call from JavaScript side in here...
        public void SendMessage(int id, string message)
        {
            // Message doing stuff here.
        }
    }
    

    ChatClient Interface

    // This provides strongly-typed methods that you'll have on the Client side but these don't exist on the server.
    public interface IChatClient
    {
        //So this method is a JS one not a .net one and will be called on the client(s)
        Task DoSomething(int id);
    
        Task NotificationUpdate(int id, string message);
    }
    

    Controller

    public class HomeController : Controller
    {
        private readonly IHubContext<ChatHub, IChatClient> _hubContext;
    
        public HomeController(IHubContext<ChatHub, IChatClient> hubContext)
        {
            _hubContext = hubContext;
        }
    
        public async Task<ActionResult> Index(int id) 
        {
    
             // This calls the method on the Client-side
             await _hubContext.Clients.All.DoSomething(id);
        }
    }