Friday, February 6, 2015

Real time multi person multi window chat application using SignalR

This article is to demonstrate real time chat application using SignalR. I develop this code for my social network Alap.Me and it has tested with many people. This is super fast light weight and it can use many people at a time with multiple chat window. For alap.me due to window size I limit it to 4 active window. This looks as like gmail or facebook chat. My server was in UK and I tested it from India it's response time was around 0.350 second. That means when one person send message to some one, it deliver it in a popup within 0.350 second. I develop it as stand alone and later integrate it with alap.me. Similar way any one can use this ready-made code to his existing code. I am offering this as open source and any one can enhance this code by informing me (just a mail is ok) and its totally free of cost for non-profit purpose. 

Prerequisite 
This has developed based on .Net 4.5 with Visual Studio 2013 express.
I have setup it on Windows Server 2008.
IIS version 7.5 (or higher).
MySQL Database, however these has just 2 standard table you can create same in other database and can configure DB layer.

Technology Used
This is SignalR Hub based application with C# code.
HTML5, CSS3 and JavaScript used for UI development.
MySQL stored procedure with ADO.Net has used.
Code developed in Visual Studio 2013 Express for Web version used.

Basic Overview how it is working
Describing later this section.

Source code
Below picture is showing my full code file list which I am going to share at below.


ChatHub.cs

using System;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace SignalRChat
{
    public class ChatHub : Hub
    {
        AlapChat objChat;
        DataTable dt;
        static Hashtable htOnlineUsers = new Hashtable();
        static List<OnlineUser> OnlineUsers=new List<OnlineUser>();
        public ChatHub()
        {
            objChat = new AlapChat();
        }
        //public void Test(string str)
        //{
        //    Clients.Caller.Hello(str + " | Message received at server reply from server." + DateTime.Now.ToShortTimeString());
        //}
        //public void Friends123()
        //{
        //    dt = objChat.GetFriendLoginStatus("7");
        //    string onlineUserList = UtilityChat.DataTableToJson(dt);
        //    Clients.Caller.friendslist(onlineUserList);
        //}
        public void clean()
        {
           
            foreach (OnlineUser user in OnlineUsers)
            {
                objChat.SetOffline(user.MyId);
            }
            OnlineUsers.Clear();
           
        }
        public void Connect(string myid)
        {
            if(OnlineUsers.Count(x=>x.MyId==myid)==0)
            {
                OnlineUsers.Add(new OnlineUser { MyId = myid, ConnectionId = Context.ConnectionId });
            }
        }
        public void loginfriends(string myid,string name)
        {
            bool isOnline=false;
            if (OnlineUsers.Count(x => x.MyId == myid) == 0)
            {
                OnlineUsers.Add(new OnlineUser { MyId = myid, ConnectionId = Context.ConnectionId, Name = name });
                objChat.SetOnline(myid);              
            }
          else //User found in Array, check if ConnectionId is same or not, if not replace it in Array
            {
                OnlineUser user = OnlineUsers.FirstOrDefault(x => x.MyId == myid);
                if(user.ConnectionId!=Context.ConnectionId)
                {
                   // Clients.Caller.Hello("Remove and readd user.");
                    OnlineUsers.Remove(user);//Delete existing and add new user
                    OnlineUsers.Add(new OnlineUser { MyId = myid, ConnectionId = Context.ConnectionId, Name = name });
                }
            }
            dt = objChat.GetFriendLoginStatus(myid);
            foreach (DataRow dr in dt.Rows)
            {
                if (dr["IsOnline"].ToString().ToLower() == "true" || dr["IsOnline"].ToString() == "1")
                    isOnline = true;
                else if (dr["IsOnline"].ToString().ToLower() == "false" || dr["IsOnline"].ToString() == "0")
                    isOnline = false;              
               
                //Inform all online friends that one user has logged in.
                if (isOnline)
                {
                    //Clients.Caller.Hello(isOnline.ToString() + " | Inform start." + DateTime.Now.ToShortTimeString());
                    try
                    {
                        OnlineUser onlineFriend = OnlineUsers.FirstOrDefault(x => x.MyId == dr["FriendUId"].ToString());
                        if (onlineFriend!=null)
                            Clients.Client(onlineFriend.ConnectionId).refreshfriendlist(myid, name); //Send new logged in user's information to all friends
                        else //User is online as DB entry but not exists in Array, hence need to set offline in DB
                        {
                            objChat.SetOffline(dr["FriendUId"].ToString());
                        }
                    }
                    catch(Exception ex)
                    {
                        Clients.Caller.Hello("Error! "+ex.Message+"<br/>"+ ex.StackTrace.ToString());
                    }
                    //Clients.Caller.Hello(isOnline.ToString() + " | Inform end." + DateTime.Now.ToShortTimeString());
                }
                else
                {
                    break;
                }
            }
           
            //Send online and offline friend list to caller
            string onlineUserList = UtilityChat.DataTableToJson(dt);
            Clients.Caller.friendslist(onlineUserList);
           
        }
        public void createnewchatid(string fromuid, string touid)
        {
            string newChatOrGroupId = objChat.GetNewChatOrGroupId();
            objChat.AddUserInChat(newChatOrGroupId,fromuid);
            objChat.AddUserInChat(newChatOrGroupId, touid);
            Clients.Caller.newchatid(newChatOrGroupId, touid);
        }
        public void sendpvtmsg(string chatorgroupid,string fromid, string fromname,string toid,string pvtmsg)
        {
            objChat.AddNewMessage(chatorgroupid, fromid, pvtmsg);
            OnlineUser onlineFriend = OnlineUsers.FirstOrDefault(x => x.MyId == toid);
            if (onlineFriend != null)
                Clients.Client(onlineFriend.ConnectionId).receivepvtmsg(chatorgroupid, fromid, fromname, pvtmsg);
        }
        public void nonmessage_control_info(string fromid, string fromname,string toid,string signal)//'Signal' is used to indicate, Typing, Away etc.
        {
            OnlineUser onlineFriend = OnlineUsers.FirstOrDefault(x => x.MyId == toid);
            if (onlineFriend != null)
                Clients.Client(onlineFriend.ConnectionId).incoming_control_msg(fromid, fromname, signal);
        }
       
        public override System.Threading.Tasks.Task OnDisconnected()
        {
            OnlineUser onlineUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
            if (onlineUser != null)
            {
                bool isOnline = false;
                objChat.SetOffline(onlineUser.MyId);
                dt = objChat.GetFriendLoginStatus(onlineUser.MyId);
                foreach (DataRow dr in dt.Rows)
                {
                    if(dr["IsOnline"].ToString().ToLower() == "true" || dr["IsOnline"].ToString() == "1")
                        isOnline=true;
                    else if(dr["IsOnline"].ToString().ToLower() == "true" || dr["IsOnline"].ToString() == "1")
                        isOnline=false;
                    //Inform all online friends that one user has logged in.
                    if (isOnline)
                    {
                        OnlineUser onlineFriend = OnlineUsers.FirstOrDefault(x => x.MyId == dr["FriendUId"].ToString());
                        if (onlineFriend != null)
                        {
                            Clients.Client(onlineFriend.ConnectionId).logoffuser(onlineUser.MyId);
                          //  Clients.Client(onlineFriend.ConnectionId).incoming_control_msg(onlineUser.MyId, onlineUser.Name, "offline"); //Not developed, keep aside for future feature
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                OnlineUsers.Remove(onlineUser);
            }
            return base.OnDisconnected();
        }      
    }
    public class OnlineUser
    {
        //public OnlineUser(string MyId, string Name, string EmailId, string ConnectionId)
        //{
        //    this.myId = MyId;          
        //    this.connectionId = ConnectionId;
        //}
        public string MyId { get; set; }
        public string ConnectionId { get; set; }
        public string Name { get; set; }
    }
}





8 comments:

Aman said...

Can you send the other class files code also on 'aman9678@gmail.com'. You have uploaded only ChatHub.cs file code. I want this complete project actually because i have the same requirement. Please do share your project on my Mail-Id. It will be a great help for me. Thanks.

Tariq said...

can you please send email me at tariq.aziz80@gmail.com the other files used in this project as well. I will enhance the code with pretty css design. Thanks

Suman Biswas said...

Hello Aman, Tariq,
I shall search my code and upload in blog, Its design was exactly like gmail chat and works excellent, I added this code in my social website alap.me (closed due to fund).

Thanks
Suman

Unknown said...

Can you send the other class files code also on 'ayoubsannouti@gmail.com'. I want this complete project actually because i have the same requirement. Please do share your project on my Mail. It will be a great help for me. Thanks.

Muhammad Shumail said...

How to create Online Cab system using .NET?

Unknown said...

Wow! great articles and very interesting to read,thanks for sharing that wonderful useful information,given programming coding was very excellent and easily observe all provided information.
dotnet

Unknown said...

thanks for sharing wonderful blog with us. its really more helpful to our institute candidates to get aware some useful knowledge keep sharing more information.
Dot Net training in Chennai

keerthisuresh said...

Great tips, and awesome way to get exert tips from everyone – you are the master of content.

Hadoop Training in Chennai