[SignalR in Asp.net Development Series] Topic 2: Use SignalR to implement cool end-to-end chat, and use signalr to cool

Source: Internet
Author: User

[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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.