rmlm
rmlm

Reputation: 59

SignalR Javascript Client: Cannot Start Connection

My connection does not start. This code worked in 1.x but in version 2 is not working.

SignalR seems to be trying to connect but without success. The hub method is never called.

Attached sending an image with SignalR debug.

Javascript:

<script type="text/javascript">

    $.connection.hub.logging = true;
    var options = { transport: ['webSockets', 'longPolling'] };

    $(function() {
        var userHub = $.connection.userHub;

        //Iniciar connecção
        window.hubReady = $.connection.hub.start(options);

        window.hubReady.done(function () {
            userHub.server.ini();
        });

        userHub.client.iniDone = function (connectionId) {
            console.log(connectionId);
        };

        $.connection.hub.connectionSlow(function() {
            console.log('slow connection...');
        });

        window.hubReady.fail(function(error) {
            console.log(error);
        });

        $.connection.hub.disconnected(function() {
            setTimeout(function() {
                $.connection.hub.start();
            }, 2000);
        });

    });

</script>

Hub:

[HubName("userHub")]
public class UserHub : Hub
{
    public void Ini()
    {
        Clients.Client(Context.ConnectionId).iniDone(string.Format("Conectado com o id: {0}", Context.ConnectionId));
    }

    public override Task OnConnected()
    {

        var connectionId = Context.ConnectionId;
        var email = string.IsNullOrWhiteSpace(Context.User.Identity.Name) ? Context.Headers["email"] : Context.User.Identity.Name;


        if (email != null && connectionId != null)
            UserData.GetInstance(email).ConnectionsIds.Add(connectionId);

        return base.OnConnected();
    }

    public override Task OnDisconnected()
    {

        var connectionId = Context.ConnectionId;
        var email = string.IsNullOrWhiteSpace(Context.User.Identity.Name) ? Context.Headers["email"] : Context.User.Identity.Name;


        if (email != null && connectionId != null)
            UserData.GetInstance(email).ConnectionsIds.Remove(connectionId);

        return base.OnDisconnected();
    }
}

Debug:

SignalR Debug Image

EDIT:

I found the problem! The GetInstance method of my Singleton has problems.

public static UserData GetInstance(string username)
{
    if (_sharedUsers == null) 
        lock (_lockCreate) 
                _sharedUsers = new Dictionary<string, UserData>(); 

    if (!_sharedUsers.ContainsKey(username)) 
        lock (_lockAdd) 
            _sharedUsers.Add(username, new UserData(username)); 

    return _sharedUsers[username];
}

the method stops always here: lock (_lockAdd)

I want to save all user connectionsIds Any ideas?

Thanks

Upvotes: 2

Views: 7772

Answers (2)

Amund Midtskog
Amund Midtskog

Reputation: 219

Had the same problem for so long, so gave up the whole signalR at some point, but had to pick it up again for our project:

I have written an answer which might lead you and others on the right track (step by step)...In the answer I am using PersistentConnection rather than Hub, but the principle should be the same:

https://stackoverflow.com/a/25304790/3940626

Upvotes: 0

Matt Tester
Matt Tester

Reputation: 4814

Try moving the client method subscription to be before you connect. If it's not registered by the time the connection is started, then it will not be callable from the server.

So change it to the following:

$(function() {
    var userHub = $.connection.userHub;

    //Register Client handlers first
    userHub.client.iniDone = function (connectionId) {
        console.log(connectionId);
    };

    //Now you can connect.
    window.hubReady = $.connection.hub.start(options);

    window.hubReady.done(function () {
        userHub.server.ini();
    });

    $.connection.hub.connectionSlow(function() {
        console.log('slow connection...');
    });

    window.hubReady.fail(function(error) {
        console.log(error);
    });

    $.connection.hub.disconnected(function() {
        setTimeout(function() {
            $.connection.hub.start();
        }, 2000);
    });

});

Edit

Based on your comment around a server error in the OnConnected method, it seems like you may have a two problems then. Isolate the connection tracking part out (just comment it out) to get the full round-trip going between client and server. Then add back the connection tracking which is possibly a DB connection error - check the server logs.

Edit

In terms of storing the user connections, you've a few options.

Use ConcurrentDictionary:

One of the simplest is storing in a static ConcurrentDictionary, similar to what you have. Try to avoid the use of so many locks - using a ConcurrentDictionary means you'll actually end up with none.

e.g.

    public class UserData
    {
        public UserData(string username)
        {
            UserName = username;
            ConnectionIds = new HashSet<string>();
        }

        public string UserName { get; private set; }
        public HashSet<string> ConnectionIds { get; private set; } 
    }

    public static class ConnectionStore
    {
        private static readonly ConcurrentDictionary<string, UserData> _userData = new ConcurrentDictionary<string, UserData>();

        public static void Join(string username, string connectionId)
        {
            _userData.AddOrUpdate(username, 
                u => new UserData(u),                   /* Lambda to call when it's an Add */
                (u, ud) => {                            /* Lambda to call when it's an Update */
                    ud.ConnectionIds.Add(connectionId);
                    return ud;
            });
        }
    }

See MSDN for more info: http://msdn.microsoft.com/en-us/library/ee378675(v=vs.110).aspx

Use a database:

The other option is to store in a database (using Entity Framework) which has the added benefit of tracking user data across server recycles.

Have a look at http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections which shows all these options a couple of others.

Upvotes: 1

Related Questions