5

I'm trying to figure out how to invoke a method on a strongly typed hub from the server. I'm using .Net-Core 2.0

I have a stongly typed hub interface:

public interface IMessageHub
{
    Task Create(Message message);
}

and a hub which looks like so:

public class MessageHub: Hub<IMessageHub>
{
    public async Task Create(Message message)
    {
        await Clients.All.Create(message);       
    }
}

Normally on the server I might push content to the client like so:

[Route("api/[controller]")]
public MessagesController : Controller
{
       IHubContext<MessagesHub> context;
       public MessagesController(IHubContext<MessagesHub> context)
       {
           this.context = context;
       }

       public Message CreateMessage(Message message)
       {
          this.context.Clients.All.InvokeAsync("Create", message);
          return message;
       }
}

How can I invoke a method on the statically typed hub or do I have a misconception on how hubs work?

johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • See https://stackoverflow.com/questions/46904678/call-signalr-core-hub-method-from-controller/46906849#46906849 . In solution 2 you will find the solution. – Stephu Nov 30 '17 at 06:50
  • @Tester thanks I tried doing that before, but I simplified the question, my real issue is that what if my client interface is Generic which takes in a DTO to push to the client? – johnny 5 Nov 30 '17 at 06:59

2 Answers2

7

Yes you can. Here is the sample step by step:

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" };
    }
  }
Stephu
  • 3,236
  • 4
  • 21
  • 33
  • I’ll make this correct correct because this is the answer, but do you know a way I can do this if my interface type takes in a generic parameter – johnny 5 Nov 30 '17 at 07:14
  • @johnny 5 at the moment I don't know. I must test first today evening – Stephu Nov 30 '17 at 07:19
  • Thanks, I’m stuck with some major architecture issues, I’m not even sure if what I want to do is possible, I’m also looking for an invariant version of IHubContext I might have to just redesign everything – johnny 5 Nov 30 '17 at 07:23
  • 4
    I did not understand why there is a `Send` method in `ChatHub` itself since you are not actually using that in `DemoController`. I tested this and you can just remove the method in `ChatHub` and it will still work fine. It is a pity that you cannot use that `Send` method in `ChatHub`. You could then encapsulate there to what clients you want to send and such. – Wim Deblauwe Sep 27 '18 at 10:55
  • It's a sample. You are right in this case it's not used. Its only there to show others that it is also possible to call methods direct on hubs. In some cases I see no reason why to combine signalr with web api. For example insead of a http get you can also call a method on the hub which return an object.... – Stephu Sep 27 '18 at 19:41
  • Is it possible to apply this approach with **Microsoft.AspNet.SignalR;**? Or what should be changed in order to transform it for Microsoft.AspNet.SignalR;? – Jack Jul 22 '19 at 09:45
  • Calling the Send method is useful if I have to do some complex logic that has to be done before sending message to clients. If I cannot call "Send" method from the controller, I have to implement my logic before every call... and is not the best solution I think. – Fabien Sartori Nov 22 '19 at 12:39
  • how do you prepare IHubContext _chatHubContext; for test code? I am stuck. cant prepare hubcontext for test – Habibul Hasan Aug 26 '20 at 16:37
  • 1
    _chatHubContext.Clients.All.BroadcastMessage("test", "test"); doesn't call hub method but clients directly. – Mariusz Mar 30 '21 at 14:35
0

so the send method in ChatHub is not really relevant in the example. in fact, just define the method in ITypedHubClient and no implementation is required, correct? singalR will magically translate the call on the server side as SendAsync('BroadcastMessage', blah blah)

koo9
  • 409
  • 5
  • 15