0

I am quite new to SignalR and C#. I have made a simple chat app following these Microsoft's official documentation.

I want that to display total number of connected clients and the list of these connected users. I'd like to do an in-memory approach by storing the users in a dictionary, but I'm having trouble integrating it into the current app.

I'm confused between whether to use OnConnectedAsync(), OnDisconnectedAsync(Exception exception) or getConnectedUsers(). And afterwards, how do I link the results to my front end (cshtml & javascript).

Here is my code so far:

Hub

using Microsoft.AspNetCore.SignalR;
using Hub = Microsoft.AspNetCore.SignalR.Hub;

namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
        // Chathub inherits from SignalR Hub Class 
        // centralized console through which we handle the interaction between the server and all connected clients

        // Public hub methods
        public async Task SendMessage(string user, string message)
        { 
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }

        // Overridable hub methods

    }


}

Jason Pan
  • 15,263
  • 1
  • 14
  • 29
jvcent
  • 11
  • 1

1 Answers1

0

I have a sample demo about this requirement and ConcurrentDictionary is thread-safe. Hope the code snippet below useful to you.

Test Result

enter image description here

Program.cs

...
builder.Services.AddSingleton<MainHub>();
builder.Services.AddSignalR().AddNewtonsoftJsonProtocol(opts => opts.PayloadSerializerSettings.TypeNameHandling = TypeNameHandling.Auto); 
...

Method inside Hub Class, MainHub.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections.Features;
using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace SignalRMiddleawre.Hubs
{

    //[Authorize]
    public partial class MainHub : Hub
    {
        public static ConcurrentDictionary<string?, List<string>>? ConnectedUsers;

        public MainHub()
        {
            ConnectedUsers  = new ConcurrentDictionary<string?, List<string>>();
        }

        public override async Task OnConnectedAsync()
        {

            //// Get HttpContext In asp.net core signalr
            //IHttpContextFeature hcf = (IHttpContextFeature)this.Context.Features[typeof(IHttpContextFeature)];
            //HttpContext hc = hcf.HttpContext;
            //string uid = hc.Request.Path.Value.ToString().Split(new string[] { "/", "" }, StringSplitOptions.RemoveEmptyEntries)[1].ToString();

            string? userid = Context.User?.Identity?.Name;
            if (userid == null || userid.Equals(string.Empty))
            {
                Trace.TraceInformation("user not loged in, can't connect signalr service");
                return;
            }
            

            Trace.TraceInformation(userid + "connected");
            // save connection
            List<string>? existUserConnectionIds;
            ConnectedUsers.TryGetValue(userid, out existUserConnectionIds);
            if (existUserConnectionIds == null)
            {
                existUserConnectionIds = new List<string>();
            }
            existUserConnectionIds.Add(Context.ConnectionId);
            ConnectedUsers.TryAdd(userid, existUserConnectionIds);

            //await Clients.All.SendAsync("ServerInfo", userid, userid + " connected, connectionId = " + Context.ConnectionId);
            await base.OnConnectedAsync();
        }


        public async Task ListConnectedUsers()
        {
            List<string?> data = ConnectedUsers.Keys.ToList();
            await Clients.All.SendAsync("ListConnectedUsers", data);
        }
    }
}

Client Side Code

...
connection.on("ListConnectedUsers", function (data) {
    var li = document.createElement("li");
    document.getElementById("messagesList").appendChild(li);
    li.textContent = `System says : Current Users :` + data;
});

Test Api Code

using AspCore7_Web_Identity.Areas.Identity.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using OfficeOpenXml;
using SignalRMiddleawre.Hubs;
using System.Net.Http;
using System.Web.Services.Description;

namespace AspCore7_Web_Identity.Controllers
{
    public class TestController : Controller
    {
        private readonly ILogger<TestController> _logger;
        private readonly IHubContext<MainHub> _hubContext;
        private readonly MainHub _hub;

        public TestController(ILogger<TestController> logger, IHubContext<MainHub> hubcontext, MainHub hub)
        {
            _logger = logger;
            _hubContext = hubcontext;
            _hub = hub;
        }

        public IActionResult CheckConnectedUsers()
        {
            _hub.ListConnectedUsers();

            return Ok("Success");
        }
    }
}
Jason Pan
  • 15,263
  • 1
  • 14
  • 29
  • Thank you for your answer. But do you know how I should alter my cshtml and js files to display the connected users as a list on the page instead? – jvcent May 25 '23 at 09:31