离线SignalR聊天

时间:2019-10-14 09:48:59

标签: asp.net asp.net-mvc asp.net-core signalr

我有一个在线聊天室,工作正常。但是,我希望能够向离线用户发送消息。如何修改下面的代码以实现此更改?

我想将ConnectedUsers更改为AllUsers,但是对于离线用户,我没有ConnectionId。

ChatHub.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using catchme.bg.Data;
using catchme.bg.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace catchme.bg
{
    [Authorize]
    public class ChatHub : Hub
    {
        private CatchmeContext _context { get; set; }

        public ChatHub(CatchmeContext context) 
        {
            _context = context;
        }

        #region Data Members

        static List<UserDetail> ConnectedUsers = new List<UserDetail>();
        static List<MessageDetail> CurrentMessage = new List<MessageDetail>();
        static List<PrivateMessageDetail> CurrentPrivateMessage = new List<PrivateMessageDetail>();

        #endregion

        #region Methods

        public override async Task OnConnectedAsync()
        {
            var userName = Context.User.Identity.Name;

            var id = Context.ConnectionId;


            if (ConnectedUsers.Count(x => x.ConnectionId == id) == 0)
            {
                ConnectedUsers.Add(new UserDetail {ConnectionId = id, UserName = userName});

                CurrentMessage.Clear();

                CurrentPrivateMessage.Clear();

                foreach (var user_name in ConnectedUsers.Select(u=>u.UserName).Distinct())
                {
                    CurrentMessage.AddRange(GetMessageDetailsForUser(user_name).Result);

                    CurrentPrivateMessage.AddRange(GetPrivateMessageDetailsForUsers(Context.User.Identity.Name, user_name).Result);
                }

                // send to caller
                await Clients.Caller.SendAsync("OnConnected", id, userName, ConnectedUsers, CurrentMessage, CurrentPrivateMessage);

                // send to all except caller client
                await Clients.AllExcept(id).SendAsync("NewUserConnected", id, userName, CurrentPrivateMessage);
            }
        }


        public async Task SendMessageToAll(string message)
        {
            var userName = Context.User.Identity.Name;
            // store last 100 messages in cache
            AddMessageinCache(userName, message);

            // Broad cast message
            await Clients.All.SendAsync("MessageReceived", userName, message);
        }

        public async Task SendPrivateMessage(string toUserId, string message)
        {

            string fromUserId = Context.ConnectionId;

            var toUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == toUserId);
            var fromUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);

            if (toUser != null && fromUser != null)
            {

                // send to 
                await Clients.Client(toUserId).SendAsync("SendPrivateMessage", fromUserId, fromUser.UserName, message);

                // send to caller user
                await Clients.Caller.SendAsync("SendPrivateMessage", toUserId, fromUser.UserName, message);

                AddPrivateMessageinCache(fromUser.UserName, toUser.UserName, message);

            }

        }

        public override async Task OnDisconnectedAsync(Exception ex)
        {
            var item = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
            if (item != null)
            {
                ConnectedUsers.Remove(item);

                var id = Context.ConnectionId;
                await Clients.All.SendAsync("UserDisconnected", id, item.UserName);

            }
        }


        #endregion

        #region public Messages

        private void AddMessageinCache(string userName, string message)
        {
            var publicMessage = new MessageDetail {UserName = userName, Message = message};
            CurrentMessage.Add(publicMessage);
            _context.MessageDetails.Add(publicMessage);
            _context.SaveChanges();

            if (CurrentMessage.Count > 100)
            {
                CurrentMessage.RemoveAt(0);
                _context.MessageDetails.Remove(CurrentMessage[0]);
                _context.SaveChanges();
            }


        }

        #endregion

        #region private Messages



        private void AddPrivateMessageinCache(string userFrom, string userTo, string message)
        {
            var privateMessage = new PrivateMessageDetail { UserNameFrom = userFrom, UserNameTo = userTo, Message = message };
            CurrentPrivateMessage.Add(privateMessage);
            _context.PrivateMessageDetails.Add(privateMessage);
            _context.SaveChanges();

            var singleUserPrivateMessages = CurrentPrivateMessage.Where(u => u.UserNameFrom == userFrom && u.UserNameTo == userTo).ToList();

            if (singleUserPrivateMessages.Count > 100)
            {
                CurrentPrivateMessage.Remove(singleUserPrivateMessages.First());
                _context.PrivateMessageDetails.Remove(singleUserPrivateMessages.First());
                _context.SaveChanges();
            }


        }

        #endregion

        public async Task<List<MessageDetail>> GetMessageDetailsForUser(string userName)
        {
            return await _context.MessageDetails.Where(u=>u.UserName==userName).ToListAsync();
        }

        public async Task<List<PrivateMessageDetail>> GetPrivateMessageDetailsForUsers(string userFrom, string userTo)
        {
            return await _context.PrivateMessageDetails.Where(u => u.UserNameFrom == userFrom && u.UserNameTo== userTo).ToListAsync();
        }
    }
}

Index.cshtml

@*<div>
        <form id="send-form" action="#">
            Send a message:
            <input type="text" id="message-textbox" disabled/>
            <button id="send-button" type="submit" disabled>Send</button>
        </form>
        <ul id="messages-list"></ul>
    </div>

    @section Scripts{
        <script src="~/lib/signalr/signalr.min.js"></script>
        <script src="~/js/chat.js"></script>
    }*@

<link href="~/ChatStyle.css" rel="stylesheet" />
<link href="~/lib/jquery-ui/themes/base/jquery-ui.css" rel="stylesheet" />

@section Scripts{
    @*<script src="~/lib/jquery-ui/ui/minified/core.js"></script>*@
    <script src="~/lib/jquery-ui/jquery-ui.js"></script>
    <script src="~/lib/jquery-ui/ui/minified/widget.js"></script>
    <script src="~/lib/jquery-ui/ui/widgets/mouse.js"></script>
    <script src="~/lib/jquery-ui/ui/widgets/draggable.js"></script>
    <script src="~/lib/jquery-ui/ui/widgets/resizable.js"></script>

    <script src="~/lib/signalr/signalr.min.js"></script>
    <script src="~/js/chatjs.js"></script>

}

<div id="header">
    Chat Room
</div>
<br />
<br />
<br />

<div id="divContainer">
    @*<div id="divLogin" class="login">
            <div>
                Your Name:<br />
                <input id="txtNickName" type="text" class="textBox" />
            </div>
            <div id="divButton">
                <input id="btnStartChat" type="button" class="submitButton" value="Start Chat" />
            </div>
        </div>*@

    <div id="divChat" class="chatRoom">
        <div class="title">
            Welcome to Chat Room [<span id='spanUser'></span>]

        </div>
        <div class="content">
            <div id="divChatWindow" class="chatWindow">
            </div>
            <div id="divusers" class="users">
            </div>
        </div>
        <div class="messageBar">
            <input class="textbox" type="text" id="txtMessage" />
            <input id="btnSendMsg" type="button" value="Send" class="submitButton" />
        </div>
    </div>

    <input id="hdId" type="hidden" />
    <input id="hdUserName" type="hidden" />
</div>

chatjs.js

        $(function () {

            setScreen(false);

            var connection = new signalR.HubConnectionBuilder()
                .withUrl("/hubs/chat")
                .configureLogging(signalR.LogLevel.Information)
                .build();



            connection.start().catch(err => console.error(err.toString())).then(function () {
                registerClientMethods(connection);
                registerEvents(connection);
            });

        });

        function setScreen(isLogin) {

            if (!isLogin) {

                $("#divChat").hide();
                //$("#divLogin").show();
            } else {

                $("#divChat").show();
                //$("#divLogin").hide();
            }

        }

        function AddUser(connection, id, name, privateMessages) {

            var userId = $('#hdId').val();

            var code = "";

            if (userId == id) {

                code = $('<div class="loginUser">' + name + "</div>");

            } else {

                code = $('<a id="' + id + '" class="user" >' + name + '<a>');

                $(code).dblclick(function () {

                    var id = $(this).attr('id');

                    if (userId != id)
                        OpenPrivateChatWindow(connection, id, name, privateMessages);

                });
            }

            $("#divusers").append(code);

        }

        function AddMessage(userName, message) {
            $('#divChatWindow').append('<div class="message"><span class="userName">' +
                userName +
                '</span>: ' +
                message +
                '</div>');

            var height = $('#divChatWindow')[0].scrollHeight;
            $('#divChatWindow').scrollTop(height);
}

        function registerEvents(connection) {

            $("#btnStartChat").click(function () {

                var name = $("#txtNickName").val();
                if (name.length > 0) {
                    connection.server.connect(name);
                } else {
                    alert("Please enter name");
                }

            });


            $('#btnSendMsg').click(function () {

                var msg = $("#txtMessage").val();
                if (msg.length > 0) {

                    //var userName = $('#hdUserName').val();
                    connection.send("SendMessageToAll", msg);
                    $("#txtMessage").val('');
                }
            });


            $("#txtNickName").keypress(function (e) {
                if (e.which == 13) {
                    $("#btnStartChat").click();
                }
            });

            $("#txtMessage").keypress(function (e) {
                if (e.which == 13) {
                    $('#btnSendMsg').click();
                }
            });


        }

        function registerClientMethods(connection) {

            // Calls when user successfully logged in
            connection.on("OnConnected",
                function (id, userName, allUsers, messages, privateMessages) {

                    setScreen(true);

                    $('#hdId').val(id);
                    $('#hdUserName').val(userName);
                    $('#spanUser').html(userName);

                    // Add All Users
                    for (i = 0; i < allUsers.length; i++) {

                        AddUser(connection, allUsers[i].connectionId, allUsers[i].userName, privateMessages);
                    }

                    // Add Existing Public Messages
                    for (i = 0; i < messages.length; i++) {

                        AddMessage(messages[i].userName, messages[i].message);
                    }

                    // Add Existing Private Messages
                    for (i = 0; i < privateMessages.length; i++) {

                        AddMessage(privateMessages[i].userName, messages[i].message);
                    }



                });

            // On New User Connected
            connection.on("NewUserConnected",
                function (id, name, privateMesssages) {
                    AddUser(connection, id, name, privateMesssages);
                });



            // On User Disconnected
            connection.on("UserDisconnected",
                function (id, userName) {

                    $('#' + id).remove();

                    var ctrId = 'private_' + id;
                    $('#' + ctrId).remove();


                    var disc = $('<div class="disconnect">"' + userName + '" logged off.</div>');

                    $(disc).hide();
                    $('#divusers').prepend(disc);
                    $(disc).fadeIn(200).delay(2000).fadeOut(200);

                });

            connection.on("MessageReceived",
                function (userName, message) {

                    AddMessage(userName, message);

                });

            connection.on("SendPrivateMessage",
                function (windowId, fromUserName, message) {

                    var ctrId = 'private_' + windowId;


                    if ($('#' + ctrId).length == 0) {

                        createPrivateChatWindow(connection, windowId, ctrId, fromUserName);

                    }

                    $('#' + ctrId).find('#divMessage').append('<div class="message"><span class="userName">' +
                        fromUserName +
                        '</span>: ' +
                        message +
                        '</div>');

                    // set scrollbar
                    var height = $('#' + ctrId).find('#divMessage')[0].scrollHeight;
                    $('#' + ctrId).find('#divMessage').scrollTop(height);

                });

        }

        function OpenPrivateChatWindow(connection, id, userName, privateMessages) {

            var ctrId = 'private_' + id;

            if ($('#' + ctrId).length > 0) return;

            createPrivateChatWindow(connection, id, ctrId, userName);

            //Add Private Messages
            for (i = 0; i < privateMessages.length; i++) {

                $('#' + ctrId).find('#divMessage').append('<div class="message"><span class="userName">' +
                    privateMessages[i].userNameFrom +
                    '</span>: ' +
                    privateMessages[i].message +
                    '</div>');
            }

            // set scrollbar
            var height = $('#' + ctrId).find('#divMessage')[0].scrollHeight;
            $('#' + ctrId).find('#divMessage').scrollTop(height);

        }

        function createPrivateChatWindow(connection, userId, ctrId, userName) {

            var div = '<div id="' +
                ctrId +
                '" class="ui-widget-content draggable" rel="0">' +
                '<div class="header">' +
                '<div  style="float:right;">' +
                '<img id="imgDelete"  style="cursor:pointer;" src="/images/delete.png"/>' +
                '</div>' +
                '<span class="selText" rel="0">' +
                userName +
                '</span>' +
                '</div>' +
                '<div id="divMessage" class="messageArea">' +
                '</div>' +
                '<div class="buttonBar">' +
                '<input id="txtPrivateMessage" class="msgText" type="text"   />' +
                '<input id="btnSendMessage" class="submitButton button" type="button" value="Send"   />' +
                '</div>' +
                '</div>';

            var $div = $(div);

            // DELETE BUTTON IMAGE
            $div.find('#imgDelete').click(function () {
                $('#' + ctrId).remove();
            });

            // Send Button event
            $div.find("#btnSendMessage").click(function () {

                $textBox = $div.find("#txtPrivateMessage");
                var msg = $textBox.val();
                if (msg.length > 0) {

                    connection.send("SendPrivateMessage", userId, msg);
                    $textBox.val('');
                }
            });

            // Text Box event
            $div.find("#txtPrivateMessage").keypress(function (e) {
                if (e.which === 13) {
                    $div.find("#btnSendMessage").click();
                }
            });



            AddDivToContainer($div);

        }

        function AddDivToContainer($div) {
            $('#divContainer').prepend($div);

            $div.draggable({
                handle: ".header",
                stop: function () {

                }
            });

            ////$div.resizable({
            ////    stop: function () {

            ////    }
            ////});

        }

1 个答案:

答案 0 :(得分:4)

请遵循以下步骤。

  1. 首先在OnConnectedAsync()中,获取静态列表对象并将用户connectionId存储为 用户名。
  2. 您需要使用OnDisconnectedAsync()。因此,只要您的任何用户得到 脱机时,您将使用此方法进行调用,并且可以使用此方法获取connectionId,并从列表中找到用户名。
  3. 现在采用一种您可以管理的架构,待发送消息用户列表。加 下线的用户名。
  4. 现在,当有任何用户连接时,首先检查该用户名是否存在于 PendingToSendMessageUserList模式。
  5. 如果是,则先向他发送所有待处理的消息,然后从该消息中删除用户名 模式。

希望您会理解,您需要在技术上实施它。