Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR: Is it possible to force a connection to use a specific transport on the server side as the connection is established?

While developing a server client push mechanism using SignalR I have run into the maximum concurrent connections problem. I.e. each browser process only supports around 6 concurrent connections to the same domain.

I am currently keeping track of which users are associated with which connections and after a user has three open connections I would like to force additional connections from the same user to use long polling for a transport as opposed to web sockets. In this way I hope to avoid the problem of running out of connections entirely.

I could always do this on the client with the server providing a non SignalR mechanism to inform the client if they have run out of web socket connections and the client could then specify long polling when it opens the SignalR connection but this seems inefficient. I would really like to set the transport as appropriate when the connection opens.

Something like the following in the hub class.

    /// <summary>
    /// Chooses the correct transport depending on a users connections
    /// </summary>        
    public override Task OnConnected()
    {
        if(CanOpenWebSocketsConnection(Context.User.Identity.Name))
        {
            Connection.Transport = Connections.WebSockets;
        }
        else
        {
            Connection.Transport = Connections.LongPolling;
        }
        return base.OnConnected();                
    }
like image 251
AncientSyntax Avatar asked Jan 09 '23 05:01

AncientSyntax


1 Answers

As traditional longPolling and iFrame mechanisms SignalR transport type is initiated by Client, not Server. SignalR is simply a wrapper of these transport types. A workaround for this question is to have the Server to tell the Client to reconnect using a specific type.

Server code:

[HubName("moveShape")]
public class MoveShapeHub : Hub
{
    public override Task OnConnected()
    {
        if (Context.QueryString["transport"] == "webSockets")
        {
            return Clients.Caller.changeTransport("longPolling");
        }
    }
}

Client code:

var hubConnection = new HubConnection("http://localhost:1235/");
var hub = hubConnection.CreateHubProxy("moveShape");

hub.On<string>("changeTransport", transportName =>
    Dispatcher.InvokeAsync(() =>
    {
        if (transportName == "longPolling")
        {
            hubConnection.Stop();
            hubConnection.Start(new LongPollingTransport());
        }
    }));

await hubConnection.Start();

I have tested this solution. It works under SignalR v2.2. Here is my Github sample project. (Somehow under SignalR v0.5.2, the hubConnection does not restart once stopped).

like image 168
Jeson Martajaya Avatar answered Jan 28 '23 01:01

Jeson Martajaya