diff --git a/samples/BlazorChat/BlazorChatSampleHub.cs b/samples/BlazorChat/BlazorChatSampleHub.cs index 565c1f5c..4c85ea35 100644 --- a/samples/BlazorChat/BlazorChatSampleHub.cs +++ b/samples/BlazorChat/BlazorChatSampleHub.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; @@ -8,21 +11,54 @@ namespace BlazorChat public class BlazorChatSampleHub : Hub { public const string HubUrl = "/chat"; + // cache with + private static ConcurrentDictionary> _connectedUsers = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - public async Task Broadcast(string username, string message) + public async Task Broadcast(string username, string recipient, string message) { - await Clients.All.SendAsync("Broadcast", username, message); + if (string.IsNullOrEmpty(recipient)) + { + await Clients.All.SendAsync("Broadcast", username, message); + } + else if (_connectedUsers.TryGetValue(recipient, out var connections) && connections.Count > 0) + { + await Clients.Clients(connections).SendAsync("SendToUser", username, recipient, message); + } } - public override Task OnConnectedAsync() + public override async Task OnConnectedAsync() { - Console.WriteLine($"{Context.ConnectionId} connected"); - return base.OnConnectedAsync(); + var username = Context.GetHttpContext().Request.Query["username"]; + if (_connectedUsers.TryGetValue(username, out var connections)) + { + connections.Add(Context.ConnectionId); + } + else + { + connections = new List() { Context.ConnectionId }; + } + _connectedUsers[username] = connections; + Console.WriteLine($"{Context.ConnectionId}:${username} connected"); + + await Clients.All.SendAsync("UpdateConnectedUsers", _connectedUsers.Keys); + await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception e) { - Console.WriteLine($"Disconnected {e?.Message} {Context.ConnectionId}"); + var username = Context.GetHttpContext().Request.Query["username"]; + if (_connectedUsers.TryGetValue(username, out var connections) && connections.Contains(Context.ConnectionId)) + { + connections.Remove(Context.ConnectionId); + _connectedUsers[username] = connections; + if (connections.Count == 0) + { + _connectedUsers.Remove(username, out var removed); + } + } + Console.WriteLine($"Disconnected {e?.Message} {Context.ConnectionId}:${username}"); + + await Clients.All.SendAsync("UpdateConnectedUsers", _connectedUsers.Keys); await base.OnDisconnectedAsync(e); } } diff --git a/samples/BlazorChat/Pages/ChatRoom.razor b/samples/BlazorChat/Pages/ChatRoom.razor index 01fd7a25..ab655e89 100644 --- a/samples/BlazorChat/Pages/ChatRoom.razor +++ b/samples/BlazorChat/Pages/ChatRoom.razor @@ -29,6 +29,15 @@ else You are connected as @_username + +

Connected users:

+
    + @foreach (var user in _connectedUsers) + { +
  • @user
  • + } +
+ // display messages
@foreach (var item in _messages) @@ -40,12 +49,20 @@ else else {
-
@item.Username
+
From: @item.Username
+ @if (!string.IsNullOrWhiteSpace(item.RecieverUsername)) + { +
To: @item.RecieverUsername
+ }
@item.Body
} }
+
+ + +
@@ -61,12 +78,18 @@ else // on-screen message private string _message; + // on-screen recipientUsername + private string _recipientUsername; + // new message input private string _newMessage; // list of messages in chat private List _messages = new List(); + // list of messages in chat + private List _connectedUsers = new List(); + private string _hubUrl; private HubConnection _hubConnection; @@ -94,10 +117,16 @@ else _hubUrl = baseUrl.TrimEnd('/') + BlazorChatSampleHub.HubUrl; _hubConnection = new HubConnectionBuilder() - .WithUrl(_hubUrl) + .WithUrl($"{_hubUrl}?username={_username}") .Build(); + _hubConnection.On>("UpdateConnectedUsers", (userList) => + { + _connectedUsers = userList.ToList(); + InvokeAsync(StateHasChanged); + }); _hubConnection.On("Broadcast", BroadcastMessage); + _hubConnection.On("SendToUser", SendToUser); await _hubConnection.StartAsync(); @@ -117,7 +146,18 @@ else _messages.Add(new Message(name, message, isMine)); // Inform blazor the UI needs updating - StateHasChanged(); + InvokeAsync(StateHasChanged); + } + + private void SendToUser(string senderUsername, string recieverUsername, string message) + { + bool isMine = senderUsername.Equals(_username, StringComparison.OrdinalIgnoreCase); + var messageObj = new Message(senderUsername, message, isMine); + messageObj.RecieverUsername = recieverUsername; + _messages.Add(messageObj); + + // Inform blazor the UI needs updating + InvokeAsync(StateHasChanged); } private async Task DisconnectAsync() @@ -138,8 +178,7 @@ else { if (_isChatting && !string.IsNullOrWhiteSpace(message)) { - await _hubConnection.SendAsync("Broadcast", _username, message); - + await _hubConnection.SendAsync("Broadcast", _username, _recipientUsername, message); _newMessage = string.Empty; } } @@ -154,6 +193,7 @@ else } public string Username { get; set; } + public string RecieverUsername { get; set; } public string Body { get; set; } public bool Mine { get; set; } diff --git a/samples/BlazorChat/Startup.cs b/samples/BlazorChat/Startup.cs index af28101e..c826a5a4 100644 --- a/samples/BlazorChat/Startup.cs +++ b/samples/BlazorChat/Startup.cs @@ -28,6 +28,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); + services.AddSignalR().AddAzureSignalR("Endpoint=https://jixinaue.service.signalr.net;AccessKey=cOKNRVvika0bEO93RytJUUyPPZu9dUl+M8mD2LK461U=;Version=1.0;"); services.AddSingleton(); }