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






4.82/5 (16投票s)
使用 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>: ' + 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>: ' + 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.asax和Global.asax.cs:设置连接超时
关注点
在此项目中,我将使用数据库来维护当前连接用户的详细信息。我还将尝试解释“Clients.All
”(将消息广播给所有已连接客户端)和Clients.Group(GroupName,Exceptional).receiveMessage
”(将消息发送到特定连接的群组)之间的区别。
我将仅使用数据库来维护连接到Hub的用户的详细信息。使用数据库维护聊天记录的工作留给读者。祝您有美好的一天。
历史
不会添加新的更新。