3
votes

The infrastructure is the following:

  • ASP.NET MVC app on one server
  • ASP.NET Web Api 2 on second server
  • SignalR with multiple Hubs on thirth server

When some controller action is executed on the WebApi I need to send request to the SignalR server and invoke some Hubs methods. Often I need to invoke multiple different methods from one or more hubs in single WebApi request. What I do now is create new HubConnection and create HubProxy for every Hub method that I need to invoke in a singe request, so if I need to invoke 5 different hub methods I create 5 different connections. I doubt this is the right way to manage the HubConnection. Should I create only one HubConnection per each WebApi request or should I keep only one HubConnection per application lifetime (All api requests use one instance).

public class HubsConnectionManager
{
    //private static HubConnection hubConneciton; - Use this for per application singleton
    //private HubConnection hubConnection; - Use this for per request singleton

    public async Task<IHubProxy> GetHub<THub>() where THub : Hub
    {
        var hubConnection = new HubConnection("http://localhost:51489/");

        string hubName = typeof(THub).Name;
        IHubProxy hub = hubConnection.CreateHubProxy(hubName);

        await hubConnection.Start();
        return hub;
    }
}

HubsConnectionManager manager; // HubsConnectionManager is a singleton per request
IHubProxy hub = await manager.GetHub<NotificationHub>();
await hub.Invoke("PushNotificationToUser", notificaiton);

If I were to implement the per request singleton solution I would add private HubConnection member in the HubsConnectionManager and if I were to implement the per application solution, I would add private static HubConnection and use them in the GetHub method. Which solution is the right one and how should I implement it? How should I handle the situations when the connection has been lost?

1
Have you tried calling the hub method without actually creating the connection as described here: asp.net/signalr/overview/guide-to-the-api/…?Pawel
@Pawel Yes I have. This approach worked when I hosted both the SignalR and the WebApi project on the same server so they operated on the same AppPool. But now as they are both hosted on different servers I have to create a connection. Note that it is still valid if I use GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>() on the WebApi but no clients will receive any notifications since I have loaded the Hub from the local WebApi context which is empty because the SignalR context is on a different server. Thanks for the response.Dejan Bogatinovski
Sorry, I missed that this is on separate servers. I think the best would be to maintain one SignalR connection between servers instead of opening a connection for each request - opening SignalR connections is heavy - it requires sending 3 http requests. You may always consider not using SignalR on the other server but just send and httpRequest to the other server where you would use ConnectionManager if you wanted to push some data to clients.Pawel
Thanks for the information. I didn't know that opening a connection requires that much work. I also think that the better solution is to create one connection between servers but I'd have to gather more information about how to create robust implementation.Dejan Bogatinovski
@blalond I also concluded that creating a new connection is very unperformant and overkill. I think the solution 2 with the WebApi surface on the SignalR server is quite robust and will do the job with great performance. However, I decided to go with solution 1 where I maintain one client connection with the Hub directly from my origin WebApi. I setup connection lifetime handling events to manage the connection properly. docs.microsoft.com/en-us/aspnet/signalr/overview/…Dejan Bogatinovski

1 Answers

0
votes

i also think that using reflection like that with something that can be cached in a string is a better way to keep the garbage collector happy. depends on ur scale i guess.