You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:20:37