Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

SignalR with ASP.NET – One-to-one and Group Chat with Database Record Maintained at Server

0.00/5 (No votes)
17 May 2016 1  
Use of signalR for one-to-one and group chat

Introduction

The signalR feature in its ASP.NET Web Application Framework is the one which was able to switch maximum developers to ASP.NET. The simplicity of signalR, both at server and client side along with cross domain real time communication is awesome. Not only the simplicity but also the speed was too good.

Background

Out of many uses of real time communication using SignalR, chat is one of the important features. Many articles tell either about one-to-one or group chat. But, in this article, I am going to explain both. Also, I am giving the database use to maintain record of connected users.

Using the Code

Here, I am going to explain the use of signalR for one-to-one and group chat. I have developed an ASP.NET web server which runs signalR while html page and android apps are in a role of clients. Here I am giving example of html page client. I would write two different signalR hub classes for one-to-one and group chat in a single application. Also uses MS SQL database to maintain details of connected users. Let us first go through one-to-one chat starting with server side code part.

SignalRChatHub is my SignalR class for one-to-one chat.

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

[HubName("signalRChatHub")]” represents the custom hub name. Here I will use same name as class name. I will override the method “OnConnected()” to get connection id of connected client and inform connected client with total number of connected users.

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() is a method used to get total number of users connected to hub. I will store the connected users to MS SQL Database on successful connection. To inform the connected user, “Clients.Caller.receiveMessage” method is used where “receiveMessage” is a client side method to be called from signalR hub server.

After successful connection with hub from client side, I will call the custom method hubconnect from client to get store connected user details to MS SQL database.

[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);           
      }

Method “updaterec” is used to store user details to database. “GetUsers” will return the user names and their connection ids other than current user. To caller, the list of all online users with connection ids was send while to other online users, the information about newly connected user is send. “Exceptional” array is used to make the collection of users to whom, message is not to send. Here, in my case, only the caller is one user, to whom message was not to send.

For private chat message broadcast, I will write the following custom method.

[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” is called to broadcast the message to sender while “Clients.Client(touserid).receiveMessage” is called to broadcast the message to single receiver. Here “touserid” is the connection id of receiver.

The “OnDisconnected” method is override to remove the disconnected client from database. Also the information of disconnected client is broadcasted to other users.

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);
        }

Now, let us go through html client.

Following are the required javascript files while “signalr/hubs” is the auto generated script file.

<!--Add reference to the JQuery file-->
    <script src="Scripts/jquery-1.6.4.min.js"></script>

I use different “sender identifiers” (msgFrom) to make difference between different message types which helps me to use only one client side method to be call from server side. The following script shows the display of messages as per message types.

//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>')
                }
            };

Here is the design of html side;

<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>

Now let us start signalR class for group chat. Some peoples thinks that, “Clients.All.receiveMessage(msgFrom, msg, "");” is useful to use in group chat. But it is not correct because this will broadcast message to all connected clients and not to any particular group. To maintain different groups, use of “Groups” method of signalR is necessary.

[HubName("GroupChatHub")] is the my custom hub class name used for group chat.

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

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

Following custom method is written to connect current user to a particular group. The groupname was entered by user only.

[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);
        }

Following method is used to broadcast messages to a particular group.

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, "");
     }

The client side of group chat is almost same as per private chat. Yeah there are ew differences but I will leave this work for you.

Please find the complete code in an attachment of articles which is a running copy of project.

Important files written in a project are as listed below;

  • SignalRChatHub.cs: The signalR hub class for one-to-one chat. This file also includes the methods to update database records.
  • ChatWindow.html: The html client which runs the one-to-one chat. On run, it ask for user name. To do one-to-one chat, use connection id of a user. When any new user get connected, the user name and connection id will be displayed above chat window. Also, on new user screen, the list of allvready connected users will be displayed.
  • MyGroupHub.cs: he signalR hub class for group chat. It does not include any database methods.
  • GroupChat.html: The html client to do group chat. On run, it first ask for user name and then group name.
  • Startup.cs: The Owin configuration file.
  • Global.asax and Global.asax.cs: Connection time out set

Points of Interest

In this project, I will use database to maintain details of currently connected users. Also i will try to explain the difference between "Clients.All" which broadcasts the message to all connected clients and Clients.Group(GroupName,Exceptional).receiveMessage" which submits the message to the particular connected group.

I will use database only to maintain details of connected users to hub. The use of database to maintain chat record is leave for the reader. Have a good day.

History

No recent updates will added.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here