locked
.net core signalr in-memory storage RRS feed

  • Question

  • User1448655074 posted

    I'm trying to keep a count of the number of connections by group using https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections#in-memory-storage

    I have it all working with signalr asp.net but using the same method in .net core signalr doesn't work - the connection doesn't seem to be getting stored in the dictionary even though the class is called okay.

    There is no "mapping-users-to-connections" page for the .net core 2.2 documentation so perhaps these methods listed for asp.net are not supported?

    please could someone confirm? If so is there another way to get connection counts in .net core?

    thanks 

    Thursday, May 30, 2019 9:42 AM

All replies

  • User475983607 posted

    Managing user and groups in ASP.NET Core.

    https://docs.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-2.2

    Thursday, May 30, 2019 10:12 AM
  • User1448655074 posted

    I'm looking to get the user counts - adding to groups I can do all fine

    Thursday, May 30, 2019 11:18 AM
  • User61956409 posted

    Hi Poly,

    I'm trying to keep a count of the number of connections by group using https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections#in-memory-storage

    I have it all working with signalr asp.net but using the same method in .net core signalr doesn't work - the connection doesn't seem to be getting stored in the dictionary even though the class is called okay.

    I did a test with the following code to mapping user to connections, the code work for me, please refer to it.

    Hub Class:

    public class ChatHub : Hub
    {
        private readonly static ConnectionMapping<string> _connections =
            new ConnectionMapping<string>();
    
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    
    
        public override async Task OnConnectedAsync()
        {
            var httpContext = Context.GetHttpContext();
            var name = httpContext.Request.Query["name"];
    
            _connections.Add(name, Context.ConnectionId);
    
            await Clients.All.SendAsync("UpdateUserList", _connections.ToJson());
        }
    
        public override Task OnDisconnectedAsync(Exception exception)
        {
            var httpContext = Context.GetHttpContext();
            var name = httpContext.Request.Query["name"];
    
            _connections.Remove(name, Context.ConnectionId);
    
            return base.OnDisconnectedAsync(exception);
        }
    }

    Connection Mapping Class

    public class ConnectionMapping<T>
    {
        private readonly Dictionary<T, HashSet<string>> _connections =
            new Dictionary<T, HashSet<string>>();
    
        public int Count
        {
            get
            {
                return _connections.Count;
            }
        }
    
        public void Add(T key, string connectionId)
        {
            lock (_connections)
            {
                HashSet<string> connections;
                if (!_connections.TryGetValue(key, out connections))
                {
                    connections = new HashSet<string>();
                    _connections.Add(key, connections);
                }
    
                lock (connections)
                {
                    connections.Add(connectionId);
                }
            }
        }
    
        public IEnumerable<string> GetConnections(T key)
        {
            HashSet<string> connections;
            if (_connections.TryGetValue(key, out connections))
            {
                return connections;
            }
    
            return Enumerable.Empty<string>();
        }
    
        public void Remove(T key, string connectionId)
        {
            lock (_connections)
            {
                HashSet<string> connections;
                if (!_connections.TryGetValue(key, out connections))
                {
                    return;
                }
    
                lock (connections)
                {
                    connections.Remove(connectionId);
    
                    if (connections.Count == 0)
                    {
                        _connections.Remove(key);
                    }
                }
            }
        }
    
        public string ToJson()
        {
            var entries = _connections.Select(d =>
                string.Format("\"{0}\": [\"{1}\"]", d.Key, string.Join(",", d.Value)));
            return "{" + string.Join(",", entries) + "}";
        }
    }

    HTML+JavaScript

    <h1>Chat</h1>
    
    <div class="container">
        <div class="row">&nbsp;</div>
        <div class="row">
            <div class="col-6">&nbsp;</div>
            <div class="col-6">
                @*User..........<input type="text" id="userInput" />
                <br />*@
                Message...<input type="text" id="messageInput" />
                <input type="button" id="sendButton" value="Send Message" />
                <br />
                <h2>Online User</h2>
                <ul id="user_list"></ul>
            </div>
        </div>
        <div class="row">
            <div class="col-12">
                <hr />
            </div>
        </div>
        <div class="row">
            <div class="col-6">&nbsp;</div>
            <div class="col-6">
                <ul id="messagesList"></ul>
            </div>
        </div>
    </div>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/signalr/dist/browser/signalr.js"></script>
    <script>
        "use strict";
    
        var username = prompt('Enter your name:', '');
        //$('#displayname').val(username);
    
        var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub?name=" + username).build();
    
        //Disable send button until connection is established
        document.getElementById("sendButton").disabled = true;
    
        connection.on("ReceiveMessage", function (user, message) {
            var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
            var encodedMsg = user + " says " + msg;
            var li = document.createElement("li");
            li.textContent = encodedMsg;
            document.getElementById("messagesList").appendChild(li);
        });
    
        //display users
    
        connection.on("UpdateUserList", function (userc) {
            console.log(userc);
            $('#user_list').empty();
    
            $.map(JSON.parse(userc), function (val,k) {
                console.log('Key: ' + k + ' Value: ' + val + ';');
                var userinfo = "User Name: <b>" + k + "</b>, Connections: " + val;
    
                $('#user_list').append('<li>'+ userinfo + '</li>');
            })
        });
    
        connection.start().then(function () {
            document.getElementById("sendButton").disabled = false;
        }).catch(function (err) {
            return console.error(err.toString());
        });
    
        document.getElementById("sendButton").addEventListener("click", function (event) {
            //var user = document.getElementById("userInput").value;
            var user = username;
            var message = document.getElementById("messageInput").value;
            connection.invoke("SendMessage", user, message).catch(function (err) {
                return console.error(err.toString());
            });
            event.preventDefault();
        });
    </script>

    Test Result

    With Regards,

    Fei Han

    Friday, May 31, 2019 7:05 AM
  • User-1606305799 posted

    Hi Fei,

    Would you mind sharing how you defined your endpoint? I've the following under Startup:

    endpoints.MapHub("/hubs/chat");

    Edit: Neverrmind... Noticed you can simply pass query parameters to the URL when using the HubConnectionBuilder.

    Regards,

    David

    Friday, April 17, 2020 12:20 AM