6

I have been trying to used the following approach in my ASP.NET MVC project where Microsoft.AspNet.SignalR library is used:

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:

public class DemoController : Controller
{   
  IHubContext<ChatHub, ITypedHubClient> _chatHubContext;

  public DemoController(IHubContext<ChatHub, ITypedHubClient> chatHubContext)
  {
    _chatHubContext = chatHubContext;
  }

  public IEnumerable<string> Get()
  {
    _chatHubContext.Clients.All.BroadcastMessage("test", "test");
    return new string[] { "value1", "value2" };
  }
}

However, there is no IHubContext<THub,T> Interface in Microsoft.AspNet.SignalR library and I for this reason I cannot use IHubContext with two parameters (IHubContext<ChatHub, ITypedHubClient> _chatHubContext;). So, I am wondering if it is possible to a DI library or method. If so, how to fix this problem?

  • Is this for core or previous version. Your tags in the question make is confusing which version you are using since core has `Microsoft.AspNetCore.SignalR.Core.dll` and namespace of the same name. – Nkosi Jul 29 '19 at 11:43
  • @Nkosi Sorry, I updated tags. The version I use for MVC and I use Microsoft.AspNet.SignalR library (not Microsoft.AspNetCore.SignalR.Core). Thanks in advance... –  Jul 29 '19 at 11:53

2 Answers2

6

Microsoft.AspNetCore.SignalR contains IHubContext for untyped hub

public interface IHubContext<THub> where THub : Hub
{
    IHubClients Clients { get; }
    IGroupManager Groups { get; }
}

and for typed hub

public interface IHubContext<THub, T> where THub : Hub<T> where T : class
{
    IHubClients<T> Clients { get; }
    IGroupManager Groups { get; }
}

As you can see from declarations the THub parameter isn't used anywhere and in fact it exists for dependency injection purposes only.

Microsoft.AspNet.SignalR in it's turn contains the following IHubContext declarations

// for untyped hub
public interface IHubContext
{
    IHubConnectionContext<dynamic> Clients { get; }
    IGroupManager Groups { get; }
}

// for typed hub
public interface IHubContext<T>
{
    IHubConnectionContext<T> Clients { get; }
    IGroupManager Groups { get; }
}

As you can see in this case the interfaces don't contain THub parameter and it's not needed because ASP.NET MVC doesn't have built in DI for SignalR. For using typed client it's sufficient to use IHubContext<T> in your case. To use DI you have to "manually inject" hub context as I described it here.

Alexander
  • 9,104
  • 1
  • 17
  • 41
  • You rock!.. Thanks a lot for your helps and wonderful explanations... The problem was solved now and I can proceed to complete my SignalR implementation :) –  Jul 30 '19 at 12:29
  • Just a question: **1)** As I use multiple hubs as ChatHub, I think it is better to use multiple interface as: ITypedHubClient > ChatHub, ITypedHubClient2 > ChatHub2, etc. Is that true? **2)** As far as I know I implement the methods that are called from Client in ITypedHubClient and I implement the methods that are called from Server in the Hubs (i.e. ChatHub). Is that true? –  Jul 30 '19 at 12:33
  • 1
    @hexadecimal 1) I think so too. 2) Methods defined in `Hub` are called from client (js) - it means that js calls a function in hub and it fires on server. Methods defined in `ITypedHubClient` are called from server and fires on client - there is no implementation of the interface on server so it calls method on client side. Hope this helps – Alexander Jul 30 '19 at 13:16
  • I also a little bit confused on "Why do we use ITypedHubClient Interface at here? I think we use ITypedHubClient for dependency injection (passing to the constructor of the Controller) and separate the methods that are called from server. Is that true? Or is there any other reason for that approach? –  Jul 30 '19 at 13:53
  • 1
    @hexadecimal This is not quite right. We use `ITypedHubClient` in order to leverage strong typing in C# instead of working with `dynamic`. You can omit using this interface but in this case when you write a code calling client methods from server you won't be prompted with autocompletion of existing methods since you are working with `dynamic`. – Alexander Jul 30 '19 at 17:40
  • Great explanations, I learned so much from your answers. Many thanks again :) –  Jul 30 '19 at 19:08
  • Do you have any idea about the SignalR hub issue on [SignalR : Cannot access default hub methods](https://stackoverflow.com/questions/57286047/signalr-cannot-access-default-hub-methods)? –  Jul 31 '19 at 08:19
0

What worked for me in a controller is

private readonly IHubContext<MsgHub,IMsgHub> HubContext;

public MyController(IHubContext<MsgHub, IMsgHub> context)
{
    HubContext = context;
}
Wowo Ot
  • 1,362
  • 13
  • 21