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

ASP.NET Chatting using WCF Services and JSon

0.00/5 (No votes)
1 Dec 2011 1  
ASP.NET chatting using WCF Services and JSon

Introduction

This post is an upgrade to my previous article 'Chat Application in ASP.NET Using AJAX (Pop-up Windows)', which has some disadvantages like storing chat messages in DB and little complex in adding to a website. I implemented WCF services in place of DB to make it easy for adding to a website. JSon is used for communication between server and client.

Using the Code

The basic idea is the same as the previous one, but it was modified to improve support to multiple browsers. When I ran the application on three major browsers, IE, Firefox, Chrome, it was working perfect.

If you already read the previous article, you can skip the work flow and go to the configuration section.

The application works as follows:

  • List of online users are displayed.

    Online users list is maintained by WCF service OnlineUsers.svc, logging an entry when a user logs into the application. The user names will be displayed as hyperlinks, with a unique chat ID (GUID) for each.

  • The current logged-in user will click on a user name to open a new chat window, and types a message. On clicking a username, the OpenChatBox() function is called with the chat ID as the parameter. When the user types any message and clicks on the Send button, the message is sent to the server and stored to the database with the chat ID supplied.
    var top = 100;
    var left = 100;
    function OpenChatBox(uid, chatid) 
    {    
        var hidUsr = $('input[id*="hidCurrentUser"]')[0];
        if (hidUsr.value == uid)
            return;
        var win;
        if (navigator.userAgent.toLowerCase().indexOf("chrome") != -1)
            win = window.open("Chat.aspx?uid=" + uid + "&cid=" + 
            chatid, "ChatWindow" + chatid.replace("-", "").replace
            ("-", "").replace("-", "").replace("-", ""), 
            "status=0,toolbar=0, menubar=0, width=480, height=620");
        else
            win = window.open("Chat.aspx?uid=" + uid + "&cid=" + 
            chatid, "ChatWindow" + chatid.replace("-", "").
            replace("-", "").replace("-", "").
            replace("-", ""), "status=0,toolbar=0, menubar=0, width=480, height=550");
            
        top = top + 50;
        if (top > screen.availHeight - 550)
            top = 100;
        left = left + 50;
        if (left > screen.availWidth - 450)
            left = 100;
    
        win.moveTo(left, top);
        chats[chats.length] = win;
        return false;
    }

    The message storing is implemented in ASP.NET as below. Here I am using class 'ChatMsg' (DataContract) to pass messages to chat service.

    private void SendMessage(string msg)
    {
        ChatServiceClient objChatService = new ChatServiceClient();
        ChatMsg cm = new ChatMsg();        
        cm.Msg = msg;
        cm.Sender = HttpContext.Current.User.Identity.Name;
        cm.Receiver = ViewState["uid"].ToString();
        cm.ChatId = ViewState["vwChatId"].ToString();
        cm.SubmittedDate = DateTime.Now;
        objChatService.SendMessage(cm);        
    }

    Chat_Flow.jpg

  • On the recipient's screen, a new pop-up window will appear.

    One every user's home page, a script is run every 5 seconds to ping the server for any messages.

    function PingServer() {
        PingServerForMsg()
        setTimeout(PingServer, 5000);
    }
    
    
    function PingServerForMsg() {
           // Use ajax to call the GetChatMsg.aspx to get any new messages.
    
            xmlHttp = GetXmlHttpObject(stateChangeHandler);
    }

    This JavaScript message will call the GetChat.aspx page for new messages. Here I am calling the WCF service '' to get messages and the messages will be sent to client in JSon. I am using 'JsonConvert' class from JSon.Net to serialize the list of messages. You no need to learn JSon for this application as the download includes the JSon ddl and no extra downloads are required.

    Code from GetChat.aspx.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using WCFChatProxy;
    using Newtonsoft.Json;
    
    public partial class GetChat : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.QueryString["p"] != null)
            {
                if (Request.QueryString["p"] == "read")
                {
                    ChatServiceClient objChat = new ChatServiceClient();
                    objChat.MessageStatusToRead(Request.QueryString["msgId"]);
                }
            }
            else if (Request.QueryString["cid"] != null)     //get messages for a 
                            //single chat window
            {
                Response.Clear();
                Response.ClearContent();
                Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
    
                ChatServiceClient objChatService = new ChatServiceClient();
                List<chatmsg> lstMsgs = objChatService.GetMessages
                    (Request.QueryString["cid"].ToString(),
                    HttpContext.Current.User.Identity.Name,
            ChatMsgStatus.Recent).ToList();
    
                string strMsg = JsonConvert.SerializeObject(lstMsgs);
    
                Response.Write(strMsg);
                Response.End();
            }
            else // get messages for the current logged in user
            {
                Response.Clear();
                Response.ClearContent();
                Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
    
                ChatServiceClient objChatService = new ChatServiceClient();
                List<chatmsg> lstMsgs = objChatService.GetMessagesByUserId
                (HttpContext.Current.User.Identity.Name).ToList();
    
                string strMsg = JsonConvert.SerializeObject(lstMsgs);
    
                Response.Write(strMsg);
                Response.End();
            }
        }
    }

    On the browser side, on getting a new message, the browser will open a pop-up if the chat ID is new, or will show the message if a pop-up is already open for the chat ID associated with the new message. And here, an additional change to the old article is that on receiving message, browser sends an acknowledgement to server and server marks the message as read.

    function stateChangeHandler() {
        //readyState of 4 or 'complete' represents that data has been returned 
        if (xmlHttp.readyState == 4 || xmlHttp.readyState == 'complete') {
            //Gather the results from the callback 
            var str = xmlHttp.responseText;
            if (str != "") {  
                var chatmsgs = eval(str);
                for (ind = 0; ind < chatmsgs.length; ind++) {
                    var senderId = chatmsgs[ind].Sender;
                    var chatId = chatmsgs[ind].ChatId;
                    var message = chatmsgs[ind].Msg;
                    var msgId = chatmsgs[ind].MsgId;
    
                    message = restoreHtmlTags(message);
                    document.getElementById('msgPanel').innerHTML += "
    " + senderId + ": " + message;
                    MessageReceived(msgId, msgCounter);
    
                    document.getElementById('msgPanel').scrollTop = 
                document.getElementById('msgPanel').scrollHeight;
                }
            }
        }
    } 
  • Users can communicate through the current window.

    The recipient can type in a message to reply back using the same window. The pop-up window has the screen Chat.aspx, which has the Chat.js reference of the JavaScript code to ping the server again every second. But this time, it uses the chat ID assigned to that window. And thus, every chat has a unique chat ID, and chat messages are maintained at the backend by the chat ID, and the pop-up windows communicates through the chat ID. An UpdatePanel is used here to avoid flickering of the chat window when the user clicks Send Message. And when a message is received by the recipient, the message is deleted at the server.

    User can type in HTML tags also to send messages with different fonts and size. Here, developers can customize the application to give end users an option to set their own styles by selecting fonts and size drop downs. Here in the below screenshot, I am typing the font color and size.

    Chat_fonts.jpg - Click to enlarge image

  • A single user can communicate with multiple users at a time.

    A user can chat with any number of users as pop-up windows are used for each chat with a unique chat ID for the chat.

    multi_browser.jpg - Click to enlarge image

Steps to Configure in Your Website

  • Create a new website or open your ASP.NET project in which you want to add the chat pages.
  • Download the attached zip file, unzip and copy folder 'ChatService' to local drive. Configure a virtual directory/Application with any name (say 'WCFChatService') in IIS and make it working under .NET 4.0. Check whether http://localhost/<your_service_app_name>/WCFChat.svc and http://localhost/<your_service_app_name>/OnlineUsers.svc are opening the browser. You can test with WCFTestClient (http://msdn.microsoft.com/en-us/library/bb552364.aspx) also.
  • Add service references to both the services in your website.
  • Add reference to Newtonsoft.Json.dll in your website. Get the DLL from 'ChatClient\Bin' if you don't want to download from JSon.Net site.
  • In your website's log-in page, on successful log-in, add the following code to add the user to online users list:
    OnlineUsersProxy.OnlineUsersServiceClient objOnlineUsers = 
            new OnlineUsersProxy.OnlineUsersServiceClient();
    Member mem = new Member();
    mem.UserId = txtUserID.Text;
    mem.DisplayName = GetDisplayNameById(mem.UserId); //write your own method
    objOnlineUsers.AddOnlineUser(mem);            
    
    //redirect home page
  • Copy Chat.aspx and GetChat.aspx to your website folder and Chat.js and ChatWindow.js files to Scripts subfolder. Copy the below tags for repeater control to your home page where you want to show online users.
  • Online users:<br />
        <asp:Repeater ID="rptrOnlineUsers" runat="server">
             <ItemTemplate>                                        
              <span style="cursor:hand;text-decoration:underline;" 
        onclick="OpenChatBox('<%#((OnlineUsersProxy.Member)
        Container.DataItem).UserId%>','<%#((OnlineUsersProxy.Member)
        Container.DataItem).ChatId%>')"><%#((OnlineUsersProxy.Member)
        Container.DataItem).DisplayName%></span><br />
             </ItemTemplate>
        </asp:Repeater><span class="Apple-tab-span" style="white-space: pre; ">    
        </span>   
    <input type="hidden" id="hidCurrentUser" runat="server" /> 
  • Add below code in Page_Load for binding online users to repeater. Here I am saving the current logged in user id in hidden field which is used later in chat.
    hidCurrentUser.Value = HttpContext.Current.User.Identity.Name;
    
    OnlineUsersProxy.OnlineUsersServiceClient wsOnlineUsers = 
            new OnlineUsersProxy.OnlineUsersServiceClient();
    rptrOnlineUsers.DataSource = wsOnlineUsers.GetOnlineUsers
                (HttpContext.Current.User.Identity.Name);
    rptrOnlineUsers.DataBind(); 
  • Run your project to test ..... :-)

Points of Interest

I hope using WCF and JSon.Net in place of DB will be a better solution, and while improving this, I got a chance to fix issues with other browsers, Firefox and Chrome.

Enhancements

  • WCF service stores the messages in memory and I implemented few methods to free memory by deleting old messages. And user can call these methods on log-out to remove logged out user messages.
  • Developers can try to implement saving the chat history.
  • The list of online users can be implemented in a user control to make it reusable and to show image of the user as it uses repeater control.
  • I used simple design for chat window and it can be changed to include the time of message and images.

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