如何确保聊天应用程序中的消息立即显示给收件人

问题描述 投票:0回答:1

我正在使用 ASP.NET Core MVC、Identity 和 SignalR 创建一对一聊天应用程序。但是,我遇到一个问题,从列表中选择用户并向他们发送消息后,该消息不会立即显示。由于我已将其保存在数据库中,因此它仅在刷新浏览器后才可见。这是我的控制器“

public class MessagingController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<AppDbContext> _userManager;
        private readonly IHubContext<MessageHub> _hubContext;

        public MessagingController(ApplicationDbContext context, UserManager<AppDbContext> userManager, IHubContext<MessageHub> hubContext)
        {
            _context = context;
            _userManager = userManager;
            _hubContext = hubContext;
        }

        public IActionResult Index()
        {
            var currentUserId = _userManager.GetUserId(User);
            var users = _userManager.Users.Where(u => u.Id != currentUserId).ToList();
            var messages = _context.Messages
                .Where(m => m.SenderId == currentUserId || m.ReceiverId == currentUserId)
                .Include(m => m.Sender)
                .Include(m => m.Receiver)
                .OrderByDescending(m => m.Timestamp)
                .ToList();
            var viewModel = new IndexViewModel
            {
                Users = users,
                Messages = messages,
                CurrentUserId = currentUserId  // Add this line to pass the current user ID to the view
            };

            return View(viewModel);
        }



      
        [HttpPost]
        public async Task<IActionResult> SendMessage(string receiverId, string content)
        {
            var senderId = _userManager.GetUserId(User);
            var senderName = _userManager.GetUserName(User);

            var message = new Message
            {
                SenderId = senderId,
                ReceiverId = receiverId,
                Content = content,
                Timestamp = DateTime.Now
            };

            _context.Messages.Add(message);
            await _context.SaveChangesAsync();

            // Send the message to the sender and the selected user using SignalR
            await _hubContext.Clients.User(senderId).SendAsync("ReceiveMessage", new { senderName, content, receiverId });
            await _hubContext.Clients.User(receiverId).SendAsync("ReceiveMessage", new { senderName, content, receiverId });

            return RedirectToAction(nameof(Index));
        }


        public IActionResult LoadMessages(string receiverId)
        {
            var currentUserId = _userManager.GetUserId(User);
            var messages = _context.Messages
                .Where(m => (m.SenderId == currentUserId && m.ReceiverId == receiverId) ||
                            (m.SenderId == receiverId && m.ReceiverId == currentUserId))
                .Include(m => m.Sender)
                .Include(m => m.Receiver)
                .OrderBy(m => m.Timestamp)
                .ToList();

            //return PartialView("_MessageListPartial", messages);
            return PartialView("_ChatPartial", messages);
        } 

这是我的观点“

@using System.Security.Claims

<!-- Index.cshtml -->
@model IndexViewModel

<div style="display: flex;">

    <!-- Left column: List of Users -->
    <div style="flex: 1; padding-right: 20px;">
        <h1>Users</h1>
        <form asp-action="SendMessage" asp-controller="Messaging" method="post">
            <label>Select a User:</label>

            @foreach (var user in Model.Users)
            {
                <label>
                    <input type="radio" name="receiverId" value="@user.Id" />
                    @user.UserName
                </label>
                <br />
            }

            <label>Message:</label>
            <input type="text" name="content" />
            <button type="submit">Send Message</button>
        </form>
    </div>
    <!-- Right column: Messages -->
    <div style="flex: 2;">
        <h1>Messages</h1>
        <ul id="messagesList">
            @if (Model.Messages.Any())
            {
                @foreach (var message in Model.Messages)
                {
                    <li>
                        @if (message.Sender != null)
                        {
                            <strong>@message.Sender.UserName:</strong>
                        }
                        else
                        {
                            <strong>Unknown User:</strong>
                        }
                        @message.Content
                    </li>
                }
            }
            else
            {
                <p>No messages available.</p>
            }
        </ul>
    </div>


</div>
<script src="~/lib/signalr/dist/browser/signalr.js"></script>
<script>
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/messageHub")
        .build();

    connection.start().then(function () {
        console.log("SignalR connection established.");
    }).catch(function (err) {
        return console.error(err.toString());
    });

    connection.on("ReceiveMessage", function (message) {
        // Handle received message, e.g., update the UI
        console.log("Received message:", message);

        // Get the current user's ID
        const currentUserId = "@User.FindFirst(ClaimTypes.NameIdentifier)?.Value";

        // Get the selected receiver's ID from the radio buttons
        const receiverId = document.querySelector('input[name="receiverId"]:checked').value;

        // Check if the message is from the sender and to the selected user
        if (message.senderId === currentUserId && message.receiverId === receiverId) {
            // Append the sent message to the messages list
            const messagesList = document.getElementById("messagesList");
            const listItem = document.createElement("li");
            listItem.innerHTML = `<strong>You:</strong> ${message.content}`;
            messagesList.appendChild(listItem);
        }

        // Check if the message is from the receiver and from the selected user
        if (message.receiverId === currentUserId && message.senderId === receiverId) {
            // Append the received message to the messages list
            const messagesList = document.getElementById("messagesList");
            const listItem = document.createElement("li");
            listItem.innerHTML = `<strong>${message.senderName}:</strong> ${message.content}`;
            messagesList.appendChild(listItem);
        }
    });
</script>
asp.net-core-mvc signalr asp.net-identity
1个回答
0
投票

调试后,在Console窗口中看到了消息的实时推送,如下。

重新检查你的代码后,我发现这行代码应该是根本原因。

const currentUserId = "@User.FindFirst(ClaimTypes.NameIdentifier)?.Value";

这个Razor语法应该在第一次渲染的时候生效,生效后会变成html和javascript脚本,后续的ReceiveMessage监听事件将无法再使用它,所以我们可以在开始的时候初始化currentUserId,然后修改后的代码如下。

@model YourNamespace.IndexViewModel

<div style="display: flex;">
    <!-- Left column: List of Users -->
    <div style="flex: 1; padding-right: 20px;">
        <h1>Users</h1>
        <form asp-action="SendMessage" asp-controller="Messaging" method="post">
            <label>Select a User:</label>
            @foreach (var user in Model.Users)
            {
                <label>
                    <input type="radio" name="receiverId" value="@user.Id" />
                    @user.UserName
                </label>
                <br />
            }

            <label>Message:</label>
            <input type="text" name="content" />
            <button type="submit">Send Message</button>
        </form>
    </div>
    
    <!-- Right column: Messages -->
    <div style="flex: 2;">
        <h1>Messages</h1>
        <ul id="messagesList">
            @if (Model.Messages.Any())
            {
                @foreach (var message in Model.Messages)
                {
                    <li>
                        @if (message.Sender != null)
                        {
                            <strong>@message.Sender.UserName:</strong>
                        }
                        else
                        {
                            <strong>Unknown User:</strong>
                        }
                        @message.Content
                    </li>
                }
            }
            else
            {
                <p>No messages available.</p>
            }
        </ul>
    </div>
</div>

<script src="~/lib/signalr/dist/browser/signalr.js"></script>
<script>
    // Global variable for the current user's ID
    const currentUserId = "@User.FindFirst(ClaimTypes.NameIdentifier)?.Value";

    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/messageHub")
        .build();

    connection.start().then(function () {
        console.log("SignalR connection established.");
    }).catch(function (err) {
        return console.error(err.toString());
    });

    connection.on("ReceiveMessage", function (message) {
        console.log("Received message:", message);

        // Append the message to the messages list
        const messagesList = document.getElementById("messagesList");
        const listItem = document.createElement("li");

        if (message.senderId === currentUserId) {
            listItem.innerHTML = `<strong>You:</strong> ${message.content}`;
        } else {
            listItem.innerHTML = `<strong>${message.senderName}:</strong> ${message.content}`;
        }

        messagesList.appendChild(listItem);
    });
</script>
© www.soinside.com 2019 - 2024. All rights reserved.