AncientSyntax
AncientSyntax

Reputation: 969

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();                
    }

Upvotes: 4

Views: 10387

Answers (1)

Jeson Martajaya
Jeson Martajaya

Reputation: 7352

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).

Upvotes: 9

Related Questions