Click here to Skip to main content
15,879,535 members
Articles / Web Development / ASP.NET / ASP.NETvNext

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

Rate me:
Please Sign up or sign in to vote.
4.82/5 (18 votes)
16 May 2016CPOL5 min read 116.7K   12.7K   38   30
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.

C#
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.

C#
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.

C#
[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.

C#
[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.

C#
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.

JavaScript
<!--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();
                })
            })

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.

JavaScript
//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;

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>

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.

C#
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.

C#
[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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
India India
I am working as an application developer for last ten years. I am mostly develop applications in ASP.NET. But, also I work in Android and Java.

Currently I am working in a company as a Sr. Application Developer. I have a team of developers and I am playing a role of team leader.

Also, I assist academic projects based on IEEE papers for ME for last ten years.

I believed on a logic development and not on a programming language. I think that, if some one was strong in logic development then he/she can easily develop an application in any programming language.

I am working on tools/domains like, image processing, networking, cloud computing, etc. Out of them, cloud computing is my favorite working domain.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Member 157891778-Aug-23 22:48
Member 157891778-Aug-23 22:48 
Questionhow to get the connection id of receiver user Pin
Member 1411844417-Jan-19 8:04
Member 1411844417-Jan-19 8:04 
Questionadmin-->multiple users, user--> only admin??? Pin
Member 136686472-Mar-18 3:28
Member 136686472-Mar-18 3:28 
QuestionHow have a chat admin. Pin
Member 101586034-May-17 9:07
Member 101586034-May-17 9:07 
AnswerRe: How have a chat admin. Pin
Rajesh Londhe9-May-17 20:26
Rajesh Londhe9-May-17 20:26 
AnswerRe: How have a chat admin. Pin
souvikcode6-Feb-18 6:34
souvikcode6-Feb-18 6:34 
QuestionIf the user are offline, what happens with the message sended ? Pin
Marcelo C Fernandes6-Apr-17 14:20
Marcelo C Fernandes6-Apr-17 14:20 
AnswerRe: If the user are offline, what happens with the message sended ? Pin
Rajesh Londhe14-Apr-17 1:38
Rajesh Londhe14-Apr-17 1:38 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Marcelo C Fernandes14-Apr-17 3:17
Marcelo C Fernandes14-Apr-17 3:17 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Rajesh Londhe14-Apr-17 3:37
Rajesh Londhe14-Apr-17 3:37 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Marcelo C Fernandes15-Apr-17 11:37
Marcelo C Fernandes15-Apr-17 11:37 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Member 1312443417-Apr-17 4:29
Member 1312443417-Apr-17 4:29 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Rajesh Londhe23-Apr-17 19:55
Rajesh Londhe23-Apr-17 19:55 
GeneralRe: If the user are offline, what happens with the message sended ? Pin
Member 1312443424-Apr-17 5:01
Member 1312443424-Apr-17 5:01 
QuestionNot able to attach the database Pin
maksha8-Mar-17 18:35
maksha8-Mar-17 18:35 
AnswerRe: Not able to attach the database Pin
Rajesh Londhe8-Mar-17 20:35
Rajesh Londhe8-Mar-17 20:35 
QuestionProject Pin
Ahmet Erol Kalkışım15-Feb-17 1:12
Ahmet Erol Kalkışım15-Feb-17 1:12 
AnswerRe: Project Pin
Rajesh Londhe17-Feb-17 6:35
Rajesh Londhe17-Feb-17 6:35 
QuestionSignalR Databse Pin
Ahmadk.net2-Jan-17 1:30
Ahmadk.net2-Jan-17 1:30 
AnswerRe: SignalR Databse Pin
Rajesh Londhe2-Jan-17 23:18
Rajesh Londhe2-Jan-17 23:18 
QuestionSave Chat in sharepoint list Pin
Member 1292659528-Dec-16 23:33
Member 1292659528-Dec-16 23:33 
AnswerRe: Save Chat in sharepoint list Pin
Rajesh Londhe29-Dec-16 19:42
Rajesh Londhe29-Dec-16 19:42 
QuestionGroup chat existing nick Pin
simpa6-Aug-16 9:46
simpa6-Aug-16 9:46 
GeneralRegarding attached zip file of project Pin
Rajesh Londhe16-May-16 20:39
Rajesh Londhe16-May-16 20:39 
Suggestionchange send_PrivateMessage to privatemessage in chatwindow.html source code zip file Pin
PrakashCs.net16-May-16 19:34
PrakashCs.net16-May-16 19:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.