This IM system is really lightweight and provides the following functions:
1. Beautify chat content
2. user online/offline prompt
3. Heartbeat packet Detection Mechanism
4. Join users for group chat
Next we will explain the specific production methods step by step.
Preparations
First of all, it is difficult for a clever man to have no rice. Here we need two things: Asp.net mvc4 project and signalr component.
Create an Asp.net mvc4 project and install the signalr component using the following command:
Install-Package Microsoft.AspNet.SignalR -Version 1.1.3
In this way, the component installation is complete.
Background Interaction
Next, create a folder named hubs in the project, and create an interface named ichathub under the folder, which is defined as follows:
Interface ichathub {// send a message to each client under the server void sendchat (string ID, string name, string message); // void sendlogin (string ID, string name) notification to the user online ); // user offline notification void sendlogoff (string ID, string name); // receives the heartbeat packet sent by the client and processes void triggerheartbeat (string ID, string name );}
Among them, the sendchat method is mainly used by the user signalr backend to send data to the foreground; The sendlogin method is mainly used to notify the user to go online; The sendlogoff method is mainly used to notify the user to go offline; the triggerheartbeat method is mainly used to receive and process heartbeat packets sent by the front end, so as to determine whether the user is disconnected (sometimes the user closes the browser directly or closes the browser in the task manager, the heartbeat packet mechanism cannot be used to detect whether a user is offline or not. Therefore, the heartbeat packet mechanism is introduced here. If the user does not send any heartbeat packet to the backend after 20 seconds, the heartbeat packet will be dropped ).
Next, add a chathub class. The implementation is as follows:
Public class chathub: hub, ichathub {private ilist <userchat> userlist = chatusercache. userlist; Public void sendchat (string ID, string name, string message) {clients. all. addnewmessagetopage (ID, name + "" + datetime. now. tostring ("yyyy/mm/dd hh: mm: SS"), message);} public void triggerheartbeat (string ID, string name) {var userinfo = userlist. where (x => X. id. equals (ID) & X. name. equals (name )). first Ordefault (); userinfo. count = 0; // receive heartbeat, Reset Counter} public void sendlogin (string ID, string name) {var userinfo = new userchat () {id = ID, name = Name }; userinfo. action + = () => {// if the user does not respond to a heartbeat packet for 20 s, it is regarded as a disconnection and an event will be thrown. Here, it will be caught and then process the user's disconnection action. Sendlogoff (ID, name) ;}; var comparison = new chatusercompare (); If (! Userlist. contains <userchat> (userinfo, comparison) userlist. add (userinfo); clients. all. loginuser (userlist); sendchat (ID, name, "<=== user" + name + "added to the discussion group ===> ");} public void sendlogoff (string ID, string name) {var userinfo = userlist. where (x => X. id. equals (ID) & X. name. equals (name )). firstordefault (); If (userinfo! = NULL) {If (userlist. remove (userinfo) {clients. all. logoffuser (userlist); sendchat (ID, name, "<=== user" + name + "exited the discussion group ===> ");}}}}
The design concept of this class includes the following parts:
First, the login information of all users is persistent to the cache set: ilist <userchat>. The definition of this cache set is as follows:
public static class ChatUserCache { public static IList<UserChat> userList = new List<UserChat>(); }
In this way, the user login information will be saved to the memory. Once a new user comes in or the old user exits, I can add or delete the entry to maintain the list, push the list to the front end. In this way, the front-end users can see in real time which users are online and which are offline.
Secondly, in the heartbeat packet detection mechanism, the front-end user sends a heartbeat packet to the processing center every five seconds. The processing center receives the heartbeat packet and sets the counter of the entity class to 0. That is to say, if the user logs on normally, the counter in the user entity is automatically set to 0 every five seconds. However, if the user does not exit through normal channels (directly close the browser or close the browser in the Task Manager ), then, the counter in the user object will increase progressively until it is added to 20th seconds, and an event will be thrown, prompting that the current user has been disconnected.
The user entity design is as follows:
Public class userchat {public userchat () {COUNT = 0; If (timer = NULL) timer = new timer (); timer. interval = 1000; // trigger timer once every 1 s. start (); timer. elapsed + = (sender, argS) => {count ++; If (count> = 20) Action (); // the user is offline and throws an event notification };} private readonly timer; public event action; Public String ID {Get; set;} public string name {Get; Set ;}// internal counter (1 increments each time ), if the server receives the heartbeat packet from the client every 5s, the Count value is reset to 0. // if the server does not receive the heartbeat packet after 20 s, the public int count {Get; set ;}}
When the user unexpectedly exits, An Action event will be thrown and we receive it in the sendlogin method. When this event is thrown, the user's logoff event will be immediately triggered and the notification will be dropped:
Public void sendlogin (string ID, string name) {var userinfo = new userchat () {id = ID, name = Name}; userinfo. action + = () => {// if the user does not respond to a heartbeat packet for 20 s, it is regarded as a disconnection and an event will be thrown. Here, it will be caught and then process the user's disconnection action. Sendlogoff (ID, name) ;}; var comparison = new chatusercompare (); If (! Userlist. contains <userchat> (userinfo, comparison) userlist. add (userinfo); clients. all. loginuser (userlist); sendchat (ID, name, "<=== user" + name + "added to the discussion group ===> ");}
This is all the content of the processing center.
Note that in the chathub class, the sendchat method, triggerheartbeat method, sendlogin method, and sendlogoff method are all methods owned by singnalr to process objects. The addnewmessagetopage method and loginuser Method, the logoffuser method is its callback method. That is to say, when you send data to the processing center through the sendchat method at the front end, you can register the addnewmessagetopage method to receive the data returned by the processing center.
Front-end logic and Layout
@ {Layout = "~ /Views/shared/_ layout. cshtml ";} <Div id = "TB" class = "easyui-panel" Title = "expert online consulting system"> <Div id = "messageboard"> <ul id = "discussion"> </ul> </div> <Div id = "usercontainer"> <ul id = "userlist"> </ul> </div> <Div id = "messagecontainer"> <textarea id = "message" class = "RTE-zone" rows = "3"> </textarea> <div> <input type = "button" id = "send" Class = "BTN" value = "send"/> <input type = "button" id = "close" class = "BTN" Value = "close"/> <input type = "hidden" id = "displayname"/> </div> @ section scripts {<style>. panel {padding: 5px; Height: auto; Min-Height: pixel PX ;}. current {color: green ;}. RTE-zone {width: 815px; margin: 0; padding: 0; Height: 160px; Border: 1px #999 solid; clear: both }. RTE-toolbar {width: 800px; margin-top: 10px ;}. RTE-toolbar Div {float: Left; width: 100% ;}. RTE-toolbar ,. RTE-toolbar a IMG {border: 0 }. RTE-Toolbar P {float: Left; margin: 0; padding-Right: 5px} # messageboard {border: 1px solid # b6df7d; float: Left; width: 800px; padding: 10px; height: pixel PX; overflow: auto; border-radius: 10px;-moz-box-Shadow: 2px 2px 5px #333333;-WebKit-box-Shadow: 2px 2px 5px #333333; box-Shadow: 2px 2px 5px #333333 ;}# usercontainer {border: 1px solid # b6df7d; float: Right; width: 200px; Height: 565px; padding: 5px; border-radius: 10px;-moz-box-Shadow: 2 Px 2px 5px #333333;-WebKit-box-Shadow: 2px 2px 5px #333333; box-Shadow: 2px 2px 5px #333333 ;}# messagecontainer {float: Left; width: 800px ;}# messagecontainer Div {float: Right ;}# message {border: 1px solid # b6df7d; width: 815px; Height: 70px; margin-top: 5px; border-radius: 10px;-moz-box-Shadow: 2px 2px 5px #333333;-WebKit-box-Shadow: 2px 2px 5px #333333; box-Shadow: 2px 2px 5px #333333 ;} # userlist Li {border-Bott OM: 1px solid # b6df7d; cursor: pointer;} # userlist Li: hover {background-color: # CCC ;}. BTN {width: 75px; Height: 25px ;}</style> <SCRIPT src = ".. /.. /content/jqueryplugin/jquery. RTE. JS "type =" text/JavaScript "> </SCRIPT> <! -- Reference the signalr library. --> <SCRIPT src = ".../scripts/jquery. signalR-1.1.4.min.js" type = "text/JavaScript"> </SCRIPT> <! -- Reference the autogenerated signalr hub script. --> <SCRIPT src = ".. /.. /signalr/hubs "> </SCRIPT> <SCRIPT >$ (function () {$ ('. RTE-zone '). RTE ("css url", "http://batiste.dosimple.ch/blog/posts/2007-09-11-1/"); // Add a reference to the automatically generated hub var chat =$. connection. chathub; // call the callback method of the hub // The addnewmessagetopage callback chat generated after the backend sendchat call. client. addnewmessagetopage = function (ID, name, message) {$ ('# discussion '). append ('<li style = "color: Blue;">' + htmlencode (name) + '</LI> <li>' + htmlencode (Message) + '</LI>')}; // The loginuser callback chat generated after the backend sendlogin is called. client. loginuser = function (userlist) {reloaduser (userlist) ;}; // The logoffuser callback chat generated after the backend sendlogoff is called. client. logoffuser = function (userlist) {reloaduser (userlist) ;};$ ('# displayname '). val (prompt ('enter your nickname: ', ''); // start link $. connection. hub. start (). done (function () {var userid = GUID (); var username = $ ('# displayname '). val (); // send the online message chat. server. sendlogin (userid, username); // click the button to send the chat content $ ('# send '). click (function () {var chatcontent = ('{message'{.contents().find('.framebody'{.html (); chat. server. sendchat (userid, username, chatcontent) ;}); // click the button to send the user offline information $ ('# close '). click (function () {chat. server. sendlogoff (userid, username); $ ("# Send" ).css ("display", "NONE") ;}); // every 5 seconds, send heartbeat packet information setinterval (function () {chat. server. triggerheartbeat (userid, username) ;}, 5000) ;}); // reload the user list var reloaduser = function (userlist) {$ ("# userlist "). children ("Li "). remove (); for (I = 0; I <userlist. length; I ++) {$ ("# userlist "). append ("<li> "+ userlist [I]. name + "</LI>") ;}// HTML-Based VaR htmlencode = function (value) {var encodedvalue =$ ('<DIV/> '{.html(value}.html (); return encodedvalue;} // ID of the guid to generate var guid = (function () {function S4 () {return math. floor (1 + math. random () x 0x10000 ). tostring (16 ). substring (1);} return function () {return S4 () + S4 () + '-' + S4 () + '-' + S4 () + '-' + S4 () + '-' + S4 () + S4 () + S4 () ;}) (); </script>}
In the above Code:
Line 3: load a Rich Text Editor
Line 3: Add a reference to the automatically generated proxy
56th rows ~ Row 3 registers the callback method to update the foreground UI.
Line 3: Open the processing center hub
Line 3: Send user online information
94th rows, send a heartbeat packet every 5 seconds
This is simple.
Run
On the page, enter the nickname:
After the input is complete, the user goes online:
The following two users are added:
User chat content record:
The user Exits normally in a simple way:
The user "Shu Yun Yan Xiang" unexpectedly exits:
I will make up the code later.
Reference: Tutorial: getting started with signalr 1.x