ASP.NET WebForms中SignalR指定用户发消息:获取toUserID方案
Solution for Getting Target User's ConnectionId in SignalR Private Chat
Step 1: Maintain User-to-ConnectionId Mapping on Server
First, create a server-side mapping between your database user IDs and SignalR ConnectionIds. Update this mapping when users connect or disconnect.
// ChatHub.cs using Microsoft.AspNet.SignalR; using System.Collections.Concurrent; public class ChatHub : Hub { // Key: Database UserID, Value: SignalR ConnectionId private static readonly ConcurrentDictionary<string, string> _userConnections = new ConcurrentDictionary<string, string>(); public override Task OnConnected() { // Pass current user's ID via query string (or use Context.User.Identity if using authentication) string currentUserId = Context.QueryString["userId"]; if (!string.IsNullOrEmpty(currentUserId)) { _userConnections.AddOrUpdate(currentUserId, Context.ConnectionId, (key, oldVal) => Context.ConnectionId); } return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { string currentUserId = Context.QueryString["userId"]; if (!string.IsNullOrEmpty(currentUserId)) { _userConnections.TryRemove(currentUserId, out _); } return base.OnDisconnected(stopCalled); } public void SendPrivateMessage(string targetUserId, string message, string dateText, string userAvatar) { // Retrieve target user's ConnectionId from the mapping if (_userConnections.TryGetValue(targetUserId, out string targetConnectionId)) { // Send message to target user Clients.Client(targetConnectionId).receivePrivateMessage(Context.ConnectionId, message, dateText, userAvatar); // Send confirmation back to sender Clients.Caller.receivePrivateMessage(Context.ConnectionId, message, dateText, userAvatar); } } }
Step 2: Bind User ID to Repeater Items
In your Chat.aspx, add a data attribute to each Repeater item to store the target user's database ID.
<!-- Chat.aspx - Repeater Template --> <asp:Repeater ID="rptUsers" runat="server"> <ItemTemplate> <div class="user-item" data-user-id='<%# Eval("UserID") %>' onclick="openChatWindow(this)"> <img src='<%# Eval("AvatarUrl") %>' alt="User Avatar" /> <span><%# Eval("UserName") %></span> </div> </ItemTemplate> </asp:Repeater>
Step 3: Store Target User ID in Chat Dialog
When a user clicks on a list item, save the target user's ID to a hidden field so it's accessible when sending messages.
<!-- Chat.aspx - Chat Dialog --> <div id="divChatWindow" style="display: none;"> <input type="hidden" id="hdnTargetUserId" /> <div id="chatMessages"></div> <input type="text" id="txtMessage" placeholder="Type your message..." /> <button onclick="sendPrivateMessage()">Send</button> </div>
// JavaScript in Chat.aspx var chatHub = $.connection.chatHub; // Pass current user's ID when starting SignalR connection $.connection.hub.qs = { "userId": "<%= CurrentUserID %>" }; // Replace with your logged-in user ID from code-behind function openChatWindow(userElement) { var targetUserId = $(userElement).data('user-id'); $('#hdnTargetUserId').val(targetUserId); $('#divChatWindow').show(); // Optional: Load chat history for the selected user here } function sendPrivateMessage() { var targetUserId = $('#hdnTargetUserId').val(); var message = $('#txtMessage').val().trim(); if (!message || !targetUserId) return; var dateText = new Date().toLocaleString(); var userAvatar = '<%= CurrentUserAvatarUrl %>'; // Replace with current user's avatar URL // Call hub method with target user's database ID (not ConnectionId) chatHub.server.sendPrivateMessage(targetUserId, message, dateText, userAvatar); $('#txtMessage').val(''); } // Client-side method to receive incoming messages chatHub.client.receivePrivateMessage = function (senderConnectionId, message, dateText, avatar) { $('#chatMessages').append(`<div class="message-item"> <img src="${avatar}" class="message-avatar" /> <div class="message-content"> <span class="message-date">${dateText}</span> <p>${message}</p> </div> </div>`); }; // Start SignalR connection $.connection.hub.start().done(function() { console.log('SignalR connection established'); });
Step 4: Bind User Data in Code-Behind
Load user data from your database and bind it to the Repeater control in Chat.aspx.cs.
// Chat.aspx.cs protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // Load users from database (exclude current logged-in user) var users = YourDataAccess.GetAllUsers().Where(u => u.UserID != CurrentUserID).ToList(); rptUsers.DataSource = users; rptUsers.DataBind(); } } // Replace with your actual logic to get logged-in user details public string CurrentUserID => Session["UserID"].ToString(); public string CurrentUserAvatarUrl => Session["AvatarUrl"].ToString();
Key Notes
- Never pass ConnectionIds directly from client: ConnectionIds can change (e.g., on page refresh), so always use your database user ID to look up the active ConnectionId on the server.
- ConcurrentDictionary: Ensures thread-safe access to the user connection mapping, critical for multi-server environments.
- Query String User ID: Passes the current user's ID to SignalR when connecting to maintain the server-side mapping.
内容的提问来源于stack exchange,提问作者Chim Di Tru
相关产品推荐
相关产品推荐

