[SignalR in Asp.net Development Series] Topic 2: Use SignalR to implement cool end-to-end chat, and use signalr to cool
I. Introduction
The previous article has introduced SignalR in detail and briefly introduced its application in Asp.net MVC and WPF. In the previous blog, we introduced the implementation of group messaging. However, for SignalR, it was born for real-time chat. Naturally, there were fewer end-to-end chats like QQ. This blog article describes how to use SignalR to implement functions similar to QQ chat.
Ii. Use SignalR to implement end-to-end chat
Before introducing the specific implementation, I will first introduce the idea of using SignalR to implement end-to-end chat. I believe that you have seen code like Clients. All. sendMessage (name, message) in the previous article, which indicates calling SendMessage of All Clients. The hub of SignalR enables real-time communication between the client and the server. To achieve end-to-end chat, you naturally cannot send messages like all clients, but you can only send messages to specific clients. Otherwise, you will not be confused and have no right to privacy. How can I send messages to a specific client? This problem is also the key to implementing the client-to-end chat function.
In addition to the All attribute, the client object has other attributes. You can press F12 in VS to view All the attributes or methods of the Clients object. The specific definitions are as follows:
public interface IHubConnectionContext <T>
{
T All {get;} // On behalf of all clients
T AllExcept (params string [] excludeConnectionIds); // All clients except parameters
T Client (string connectionId); // Specific client, this method is the key to our end-to-end chat
T Clients (IList <string> connectionIds); // The client in the parameters
T Group (string groupName, params string [] excludeConnectionIds); // Specify client group
T Groups (IList <string> groupNames, params string [] excludeConnectionIds);
T User (string userId); // specific user
T Users (IList <string> userIds); // users in parameters
}
In SignalR, for each client to mark its uniqueness, SignalR will assign it a ConnnectionId, so that we can find a specific client by ConnnectionId. In this way, when we send a message to a client, in addition to passing the message, we also need to enter the ConnectionId sent to the other party, so that the server can forward the corresponding message to the corresponding client according to the incoming ConnectionId End up. This completes the end-to-end chat function. In addition, if the user is not online, the server can save the message to the database, and wait for the corresponding client to go online, and then check whether the client needs to push the message from the database. To push the data to the client. (But at this point, the function of server-side caching data is not implemented in this blog post, and the introduction here is to let everyone understand the realization principle of QQ).
Let's sort out the realization ideas of the end-to-end chat function:
Third, the core code to achieve cool chat function
With the realization idea, the realization function is handy. Next, let us look at the code in the hub ChatHub:
public class ChatHub: Hub
{
// static properties
public static List <UserInfo> OnlineUsers = new List <UserInfo> (); // Online user list
/// <summary>
/// login connection
/// </ summary>
/// <param name = "userId"> User Id </ param>
/// <param name = "userName"> user name </ param>
public void Connect (string userId, string userName)
{
var connnectId = Context.ConnectionId;
if (OnlineUsers.Count (x => x.ConnectionId == connnectId) == 0)
{
if (OnlineUsers.Any (x => x.UserId == userId))
{
var items = OnlineUsers.Where (x => x.UserId == userId) .ToList ();
foreach (var item in items)
{
Clients.AllExcept (connnectId) .onUserDisconnected (item.ConnectionId, item.UserName);
}
OnlineUsers.RemoveAll (x => x.UserId == userId);
}
// Add online people
OnlineUsers.Add (new UserInfo
{
ConnectionId = connnectId,
UserId = userId,
UserName = userName,
LastLoginTime = DateTime.Now
});
}
// All clients synchronize online users
Clients.All.onConnected (connnectId, userName, OnlineUsers);
}
/// <summary>
/// Send private chat
/// </ summary>
/// <param name = "toUserId"> recipient user connection ID </ param>
/// <param name = "message"> Content </ param>
public void SendPrivateMessage (string toUserId, string message)
{
var fromUserId = Context.ConnectionId;
var toUser = OnlineUsers.FirstOrDefault (x => x.ConnectionId == toUserId);
var fromUser = OnlineUsers.FirstOrDefault (x => x.ConnectionId == fromUserId);
if (toUser! = null && fromUser! = null)
{
// send to
Clients.Client (toUserId) .receivePrivateMessage (fromUserId, fromUser.UserName, message);
// send to caller user
// Clients.Caller.sendPrivateMessage (toUserId, fromUser.UserName, message);
}
else
{
// Indicating that the other party is not online
Clients.Caller.absentSubscriber ();
}
}
/// <summary>
/// Called when disconnected
/// </ summary>
/// <param name = "stopCalled"> </ param>
/// <returns> </ returns>
public override Task OnDisconnected (bool stopCalled)
{
var user = OnlineUsers.FirstOrDefault (u => u.ConnectionId == Context.ConnectionId);
// Determine if the user exists, delete it if it exists
if (user == null) return base.OnDisconnected (stopCalled);
Clients.All.onUserDisconnected (user.ConnectionId, user.UserName); // Call client user offline notification
// delete users
OnlineUsers.Remove (user);
return base.OnDisconnected (stopCalled);
}
}
The above is the main implementation of the server, next look at the client's implementation code:
<script type = "text / javascript">
var systemHub = $ .connection.chatHub;
/ Connected to IM server successfully
// Mainly update online users
systemHub.client.onConnected = function (id, userName, allUsers) {
var node = chatCore.node, myf = node.list.eq (0), str = '', i = 0;
myf.addClass ('loading');
onlinenum = allUsers.length;
if (onlinenum> 0) {
str + = '<li class = "ChatCore_parentnode ChatCore_liston">'
+ '<h5> <i> </ i> <span class = "ChatCore_parentname"> Online users </ span> <em class = "ChatCore_nums"> (' + onlinenum + ') </ em> </ h5>'
+ '<ul id = "ChatCore_friend_list" class = "ChatCore_chatlist">';
for (; i <onlinenum; i ++) {
str + = '<li id = "userid-' + allUsers [i] .UserID + '" data-id = "' + allUsers [i] .ConnectionId + '" class = "ChatCore_childnode" type = "one"> < img src = "/ Content / Images / 001.jpg? '+ allUsers [i] .UserID +'" class = "ChatCore_oneface"> <span class = "ChatCore_onename"> '+ allUsers [i] .UserName +' (' + ') </ span> <em class = "ChatCore_time"> '+ allUsers [i] .LoginTime +' </ em> </ li> ';
}
str + = '</ ul> </ li>';
myf.html (str);
} else {
myf.html ('<li class = "ChatCore_errormsg"> No data </ li>');
}
myf.removeClass ('loading');
};
// Message transmission
chatCore.transmit = function () {
var node = chatCore.node, log = {};
node.sendbtn = $ ('# ChatCore_sendbtn');
node.imwrite = $ ('# ChatCore_write');
//send
log.send = function () {
var data = {
content: node.imwrite.val (),
id: chatCore.nowchat.id,
sign_key: '', // Key
_: + new Date
};
if (data.content.replace (/ \ s / g, '') === '') {
layer.tips ('Say something!', '#ChatCore_write', 2);
node.imwrite.focus ();
} else {
// All are simulated here
var keys = chatCore.nowchat.type + chatCore.nowchat.id;
// chat template
log.html = function (param, type) {
return '<li class = "' + (type === 'me'? 'ChatCore_chateme': '') + '">'
+ '<div class = "ChatCore_chatuser">'
+ function () {
if (type === 'me') {
return '<span class = "ChatCore_chattime">' + param.time + '</ span>'
+ '<span class = "ChatCore_chatname">' + param.name + '</ span>'
+ '<img src = "' + param.face + '">';
} else {
return '<img src = "' + param.face + '">'
+ '<span class = "ChatCore_chatname">' + param.name + '</ span>'
+ '<span class = "ChatCore_chattime">' + param.time + '</ span>';
}
} ()
+ '</ div>'
+ '<div class = "ChatCore_chatsay">' + param.content + '<em class = "ChatCore_zero"> </ em> </ div>'
+ '</ li>';
};
log.imarea = chatCore.chatbox.find ('# ChatCore_area' + keys);
log.imarea.append (log.html ({
time: new Date (). toLocaleString (),
name: config.user.name,
face: config.user.face,
content: data.content
}, 'me'));
node.imwrite.val (''). focus ();
log.imarea.scrollTop (log.imarea [0] .scrollHeight);
// Call the server sendPrivateMessage method to forward the message
systemHub.server.sendPrivateMessage (chatCore.nowchat.id, data.content);
}
};
node.sendbtn.on ('click', log.send);
node.imwrite.keyup (function (e) {
if (e.keyCode === 13) {
log.send ();
}
});
};
// User is offline
systemHub.client.onUserDisconnected = function (id, userName) {
onlinenum = onlinenum-1;
$ (". ChatCore_nums"). Html ("(" + onlinenum + ")");
$ ("# ChatCore_friend_list li [data-id =" + id + "]"). Remove ();
};
// start connection
$ .connection.hub.start (). done (function () {
systemHub.server.connect (userid, username); // Call the server connect method
});
</ script>
The above only lists some core code implementations. In addition, in order to achieve the cool effect, a Jquery plugin is used here: layer, the official website is: http://layer.layui.com/. This plug-in is mainly to achieve the effects of pop-up boxes and pop-up layers. To achieve cool chat special effects, you need to write JS code yourself. Since I am not very familiar with the front end, this JS special effect code is also implemented on the reference network. If you want to run to see the effect, it is recommended to download the source code to run at the end of the article.
Fourth, the final effect
After introducing the implementation ideas and implementation code, now that we have reached an exciting moment, it is to see if our implementation function can meet the needs. In addition to meeting the basic chat function, we also need to see if the interface is cool enough Dazzle.
V. Summary
After reading the above effect, is it very dazzling? If you feel dazzling, don't forget to recommend it. At this point, the content of this article is over, in the next blog post I will continue to introduce how to use Asp.net SignalR to achieve the function of the chat room.
All source code of this article: SignalR1V1Chat