65.9K
CodeProject 正在变化。 阅读更多。
Home

SignalR with ASP.NET – 一对一和群组聊天,并维护服务器上的数据库记录

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (16投票s)

2016年5月16日

CPOL

5分钟阅读

viewsIcon

121693

downloadIcon

12832

使用 signalR 进行一对一和群组聊天。

引言

ASP.NET Web Application Framework中的SignalR功能能够吸引最多的开发者转向ASP.NET。SignalR在服务器端和客户端的简洁性,以及跨域实时通信都非常棒。不仅简洁,而且速度也很好。

背景

在SignalR的众多实时通信用途中,聊天是最重要的功能之一。许多文章只介绍了“一对一”或“群组”聊天。但在本文中,我将同时介绍这两种。另外,我还将提供数据库使用方法来维护连接用户的记录。

Using the Code

在这里,我将介绍SignalR在一对一和群组聊天中的应用。我开发了一个运行SignalR的ASP.NET Web服务器,HTML页面和Android应用作为客户端。我将提供一个HTML页面客户端的例子。我将在同一个应用程序中为一对一聊天和群组聊天编写两个不同的SignalR Hub类。我还将使用MS SQL数据库来维护连接用户的详细信息。让我们先从服务器端代码部分开始,了解一对一聊天。

SignalRChatHub是我的SignalR类,用于一对一聊天。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace SignalRChat
{
    [HubName("signalRChatHub")]
    public class SignalRChatHub : Hub
    {

[HubName("signalRChatHub")]”代表自定义Hub名称。这里我将使用与类名相同的名称。我将重写“OnConnected()”方法来获取连接客户端的连接ID,并告知已连接的客户端连接用户总数。

    public override System.Threading.Tasks.Task OnConnected()
        {           
            string clientId = Context.ConnectionId;                 
            string data =clientId;
            string count = "";
            try
            {
                count= GetCount().ToString();
            }
            catch (Exception d)
            {
                count = d.Message;
            }           
            Clients.Caller.receiveMessage("ChatHub", data, count);
            return base.OnConnected();
        }

GetCount()是一个用于获取连接到Hub的总用户数的方法。我将在成功连接后将连接的用户存储到MS SQL数据库中。为了通知已连接的用户,“Clients.Caller.receiveMessage”方法被使用,其中“receiveMessage”是从SignalR Hub服务器调用的客户端方法。

在客户端成功连接到Hub后,我将调用客户端的自定义方法hubconnect,以便将连接的用户详细信息存储到MS SQL数据库。

[HubMethodName("hubconnect")]
        public void Get_Connect(String username,String userid,String connectionid)
        {
            string count = "";
            string msg = "";
            string list = "";
           try
            {
                count = GetCount().ToString();
                msg = updaterec(username, userid, connectionid);
                list = GetUsers(username);
            }
            catch (Exception d)
            {
                msg = "DB Error "+d.Message;
            }
            var id = Context.ConnectionId;       
            string[] Exceptional = new string[1];
            Exceptional[0] = id;
            Clients.Caller.receiveMessage("RU", msg, list);
            Clients.AllExcept(Exceptional).receiveMessage("NewConnection", username+" "+id,count);           
      }

updaterec”方法用于将用户详细信息存储到数据库。“GetUsers”将返回除当前用户之外的其他用户的用户名及其连接ID。将所有在线用户的连接ID列表发送给调用者,同时将新连接用户的信息发送给其他在线用户。“Exceptional”数组用于收集不应发送消息的用户。在这里,我的例子中,只有调用者是应排除的用户。

为了广播私聊消息,我将编写以下自定义方法。

   [HubMethodName("privatemessage")]
        public void Send_PrivateMessage(String msgFrom, String msg, String touserid)
        {
            var id = Context.ConnectionId;
            Clients.Caller.receiveMessage(msgFrom, msg,touserid);
            Clients.Client(touserid).receiveMessage(msgFrom, msg,id);
        }

Clients.Caller.receiveMessage”用于将消息广播给发送者,而“Clients.Client(touserid).receiveMessage”用于将消息广播给单个接收者。这里的“touserid”是接收者的连接ID。

重写“OnDisconnected”方法用于从数据库中删除已断开连接的客户端。此外,还将已断开连接的客户端信息广播给其他用户。

public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
        {
            string count = "";
            string msg = "";         
            string clientId = Context.ConnectionId;
            DeleteRecord(clientId);
            try
            {
                count = GetCount().ToString();
            }
            catch (Exception d)
            {
                msg = "DB Error " + d.Message;
            }
            string[] Exceptional = new string[1];
            Exceptional[0] = clientId;
            Clients.AllExcept(Exceptional).receiveMessage("NewConnection", clientId+" leave", count);
            return base.OnDisconnected(stopCalled);
        }

现在,让我们来看HTML客户端。

以下是所需的JavaScript文件,“signalr/hubs”是自动生成的脚本文件。

<!--Add reference to the JQuery file-->
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <!-- Add reference to the minified version of the SignarR client library -->
    <script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
    <!-- Add reference to the auto-generated proxy file -->
    <script src="signalr/hubs"></script>

$(document).ready(function () {
            var _name = window.prompt("Please Enter your name");
            $("#spnName").text(_name);
            $('#txtMsg').val('');

//This will take the user name and display it to the <span id="spnName"></span>.
//Declare the proxy instance using the auto-generated proxy class

            var chatProxy = $.connection.signalRChatHub;

            // Call the hubconnect method which saves user details at server and bind the btnClick event when connection to the hub is started

            $.connection.hub.start().done(function () {
                try {
                    chatProxy.server.hubconnect($("#spnName").text(), $("#connID").text(), $("#connID").text());
                } catch (e) { alert(e.message); }

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

                    // Send private Message to the Hub using the proxy instance

chatProxy.server.send_PrivateMessage($("#spnName").text(), $("#txtMsg").val(), $("#txtTo").val());
                    $('#txtMsg').val('').focus();
                })
            })

我使用不同的“发送者标识符”(msgFrom)来区分不同类型的消息,这有助于我只使用一个客户端方法从服务器端调用。以下脚本显示了消息根据消息类型进行的显示。

//Callback function which the hub will call when it has finished processing,
            // is attached to the proxy
            chatProxy.client.receiveMessage = function (msgFrom, msg, senderid) {
                if (msgFrom == "NewConnection") {
//displays new client connected information to other users than connected one
                    $("#usersCount").text(senderid);
                    $('#divUsers').append('<li>' + msg+ '</li>')
                }
                else if (msgFrom == "ChatHub")
                {
//displays the total online user counts and connection id of current user to himself only
                    $("#usersCount").text(senderid);
                    $("#connID").text(msg);
                }
                else if (msgFrom == "RU") {
//this will displays the result of record update in database at server side and update the list of online users
                    var online = senderid.split('#');                   
                    var length = online.length;
                    for (var i = 0; i < length; i++) {
                        $('#divUsers').append('<li>' + online[i] + '</li>')
                    }
                  
                    $('#divChat').append('<li><strong>' + msgFrom
                        + '</strong>:&nbsp;&nbsp;' + msg + '</li>')
                }
                else {
//it displays the message in message window while connection id of sender in a textbox,
                    $("#txtTo").val(senderid);
                    $('#divChat').append('<li><strong>' + msgFrom
                        + '</strong>:&nbsp;&nbsp;' + msg + '</li>')
                }
            };

这是HTML端的设计;

<div style="width: 55%; border: solid 1px Red; height: 40px">
        <h3 style="margin: 10px 0px 0px 10px">
            <span id="spnName"></span>
            <span id="connID"></span>
            <span id="usersCount"></span>
        </h3>
    </div>
    <div style="width: 55%; border: solid 1px Red; height: auto">
        <div style="height: auto" id="divUsers"></div>
        <div style="height: 70%" id="divChat"></div>
        <div style="border: dashed 1px Black; margin-top:5%;">
            <div style="float: left; width: 20%; padding: 4px">
                <input type="text" style="width: 100%" id="txtTo" />
            </div>
            <div style="float: left; width: 60%; padding: 4px">
                <input type="text" style="width: 100%" id="txtMsg" />
            </div>
            <div style="float: right; width: 15%; padding: 4px">
                <input type="button" id="btnSend" value="Send Message" style="width: 45px" />
            </div>
        </div>
    </div>

现在让我们开始用于群组聊天的SignalR类。有些人认为,“Clients.All.receiveMessage(msgFrom, msg, "");”在群组聊天中很有用。但这是不正确的,因为它会将消息广播给所有已连接的客户端,而不是任何特定群组。要维护不同的群组,必须使用SignalR的“Groups”方法。

[HubName("GroupChatHub")]是我用于群组聊天的自定义Hub类名。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalRChat
{
    [HubName("GroupChatHub")]
    public class MyGroupHub : Hub
    {

以下自定义方法用于将当前用户连接到特定群组。群组名由用户输入。

[HubMethodName("groupconnect")]
        public void Get_Connect(String username, String userid, String connectionid, String GroupName)
        {
            string count = "NA";
            string msg = "Welcome to group "+GroupName;
            string list = "";
          
            var id = Context.ConnectionId;
            Groups.Add(id, GroupName);//this will add the connected user to particular group

            string[] Exceptional = new string[1];
            Exceptional[0] = id;

            Clients.Caller.receiveMessage("Group Chat Hub", msg, list);
            Clients.OthersInGroup(GroupName).receiveMessage("NewConnection", GroupName+" "+username + " " + id, count);
            //Clients.AllExcept(Exceptional).receiveMessage("NewConnection", username + " " + id, count);
        }

以下方法用于将消息广播到特定群组。

   public void BroadCastMessage(String msgFrom, String msg, String GroupName)
        {
            var id = Context.ConnectionId;
            string[] Exceptional = new string[0];
            Clients.Group(GroupName,Exceptional).receiveMessage(msgFrom, msg, "");
        }

群组聊天的客户端与私聊几乎相同。是的,有一些小的差异,但我将这项工作留给您。

请在文章的附件中找到完整的代码,这是一个可运行的项目副本。

项目中编写的重要文件如下;

  • SignalRChatHub.cs:用于一对一聊天的SignalR Hub类。此文件还包括更新数据库记录的方法。
  • ChatWindow.html:运行一对一聊天的HTML客户端。运行时,它会要求输入用户名。要进行一对一聊天,请使用用户的连接ID。当有新用户连接时,用户名和连接ID将显示在聊天窗口上方。此外,在新用户屏幕上,将显示所有已连接用户的列表。
  • MyGroupHub.cs:用于群组聊天的SignalR Hub类。它不包含任何数据库方法。
  • GroupChat.html:用于群组聊天的HTML客户端。运行时,它首先要求输入用户名,然后是群组名。
  • Startup.cs:Owin配置文件。
  • Global.asaxGlobal.asax.cs:设置连接超时

关注点

在此项目中,我将使用数据库来维护当前连接用户的详细信息。我还将尝试解释“Clients.All”(将消息广播给所有已连接客户端)和Clients.Group(GroupName,Exceptional).receiveMessage”(将消息发送到特定连接的群组)之间的区别。

我将仅使用数据库来维护连接到Hub的用户的详细信息。使用数据库维护聊天记录的工作留给读者。祝您有美好的一天。

历史

不会添加新的更新。

© . All rights reserved.