Click here to Skip to main content
15,861,125 members
Articles / Web Development / ASP.NET

Ajax Chat Sample via Comet Ajax

Rate me:
Please Sign up or sign in to vote.
4.75/5 (7 votes)
22 Apr 2010GPL33 min read 64.9K   2.3K   53   13
An article of how you can create serious web applications via PokeIn Comet Ajax library in minutes

Let's Create a Chat Addin for your Web Site

The chat feature on the web page to provide chat between the visitors, obviously would be good. I will try to explain how you can prepare this type of web page addins via PokeIn. If you have a rush, you can download the sample project from the link above. This time, I created a sample for VB.NET too. Please don't forget, you need to download PokeIn Library and add that as a reference on your project.

ChatSampleCS

I had mentioned about the entry points of PokeIn in "this" article before. And now, I want to talk about the other parts of library.

Here is the entire Chat class of our application:

C#

C#
public class ChatApp
{
	public static Dictionary<string, /> Users = null;
	public static Dictionary<string, /> Names = null;
	string ClientID;
	string Username;
	
	public ChatApp(string clientId)
	{
		ClientID = clientId;
		Username = "";
	}
	
	~ChatApp()
	{
		lock (Users)
		{
			Users.Remove(ClientID);
		}
		lock (Names)
		{
			Names.Remove(Username);
		} 
	} 
	
	public void SetName(string user_name)
	{
		if (Username != "")
		{
			PokeIn.Comet.CometWorker.SendToClient(ClientID,
                               "alert('You already have an username!');");
			return;
		}
		bool duplicate = false;
		lock (Names)
		{
			duplicate = Names.ContainsKey(user_name);
		}
		if (duplicate)
			PokeIn.Comet.CometWorker.SendToClient(ClientID,
        			"alert('Another user is using the name you choose!
			\\nPlease try another one.');");
		else
		{
			lock (Names)
			{
				Names.Add(user_name, ClientID);
			}

			lock (Users)
			{
				Users.Add(ClientID, user_name);
			}
			Username = user_name;

			PokeIn.Comet.CometWorker.SendToClient(ClientID,
         "UsernameSet('" + PokeIn.Comet.BrowserHelper.SafeParameter(user_name) + "');"); 
		}
	}
	
	public void Send(string message) 
	{
		PokeIn.Comet.CometWorker.SendToAll("ChatMessageFrom('" +
                      PokeIn.Comet.BrowserHelper.SafeParameter(Username) + 
                      "','" + PokeIn.Comet.BrowserHelper.SafeParameter( message ) +
                      "');");
	}
}

VB.NET

VB.NET
Public Class ChatApp
    Private ClientID As String
    Public Shared Names As Dictionary(Of String, String)
    Private Username As String
    Public Shared Users As Dictionary(Of String, String)


    Public Sub New(ByVal clientId As String)
        Me.ClientID = clientId
        Me.Username = ""
    End Sub

    Shared Sub New()
        ChatApp.Users = Nothing
        ChatApp.Names = Nothing
    End Sub

    Protected Overrides Sub Finalize()
        Try
            SyncLock ChatApp.Users
                ChatApp.Users.Remove(Me.ClientID)
            End SyncLock
            SyncLock ChatApp.Names
                ChatApp.Names.Remove(Me.Username)
            End SyncLock
        Finally
            MyBase.Finalize()
        End Try
    End Sub 

    Public Sub Send(ByVal message As String)
        PokeIn.Comet.CometWorker.SendToAll(String.Concat(New String() {
            "ChatMessageFrom('", PokeIn.Comet.BrowserHelper.SafeParameter(Me.Username),
            "','", PokeIn.Comet.BrowserHelper.SafeParameter(message), "');"}))
    End Sub

    Public Sub SetName(ByVal user_name As String)
        If (Me.Username <> "") Then
            PokeIn.Comet.CometWorker.SendToClient(Me.ClientID,
                "alert('You already have an username!');")
        Else
            Dim duplicate As Boolean = False
            SyncLock ChatApp.Names
                duplicate = ChatApp.Names.ContainsKey(user_name)
            End SyncLock
            If duplicate Then
                PokeIn.Comet.CometWorker.SendToClient(Me.ClientID,
           	"alert('Another user is using the name you choose!
		\nPlease try another one.');")
            Else
                SyncLock ChatApp.Names
                    ChatApp.Names.Add(user_name, Me.ClientID)
                End SyncLock
                SyncLock ChatApp.Users
                    ChatApp.Users.Add(Me.ClientID, user_name)
                End SyncLock
                Me.Username = user_name
                PokeIn.Comet.CometWorker.SendToClient(Me.ClientID,
           	("UsernameSet('" & PokeIn.Comet.BrowserHelper.SafeParameter
			(user_name) & "');"))
            End If
        End If
    End Sub 
End Class

For every new connection, PokeIn creates an instance of this class with the clientId of connection. So, ChatApp class stores this information and waits for the username. Client side sends the username via SetName function call and if there is no same username in the Users dictionary, client side gets UsernameSet event. After it, Client can call the Send function to send messages to others.

As you can see, we created a manager class for a web application just like for a desktop application.

Let's focus on some parts of code.

Why I'm Calling "PokeIn.Comet.BrowserHelper.SafeParameter" Function for String Parameter?

C#

C#
PokeIn.Comet.CometWorker.SendToClient(ClientID, "UsernameSet('" + 
    PokeIn.Comet.BrowserHelper.SafeParameter(user_name) + "');"); 

VB.NET

VB.NET
PokeIn.Comet.CometWorker.SendToClient(Me.ClientID, 
    ("UsernameSet('" & PokeIn.Comet.BrowserHelper.SafeParameter(user_name) & "');")) 

As you know from the first article, SendToClient function sends messages to browser side to run. So, every message may have a string parameter in own function parameter list. And value of those parameters may contain some harmful characters for our JavaScript function body. To discard these types of errors easily, we can use this method.

Why We Used Destructor Function in Our Class?

C#

C#
~ChatApp()
{
	lock (Users)
	{
		Users.Remove(ClientID);
	}
	lock (Names)
	{
		Names.Remove(Username);
	} 
}

VB.NET

VB.NET
Protected Overrides Sub Finalize()
	Try
		SyncLock ChatApp.Users
			ChatApp.Users.Remove(Me.ClientID)
		End SyncLock
		SyncLock ChatApp.Names
			ChatApp.Names.Remove(Me.Username)
		End SyncLock
	Finally
		MyBase.Finalize()
	End Try
End Sub 

If the user closes the chat window, we need to remove him safely from our active user list to free resources and available names. So, when PokeIn realizes that the user is offline, it will remove the object instances the client has. In this sample, our class destructors will run and we can remove the user information from our lists.

What for Lock / SyncLock ?

"Users" and "Names" dictionaries are usable for all active users concurrently (don't forget! we have created a multiuser application). So, for thread safety, we locked the shared objects. So we know that the shared dictionaries will be accessible by the entire application safely. If you downloaded the sample application, probably you saw that I locked these shared objects every time I used them.

Tricks

  • PokeIn.Comet.BrowserHelper.RedirectPage: Allows you to redirect given client to given URL (useful for kick?:)), i.e., You can track the chat activity of each client and kick some of them via remoting their page to your application home, etc. Or some server operations may need to refresh all client pages.
  • PokeIn.Comet.BrowserHelper.SetElementProperty: You can set any property of any client side object from the server side.
    There will be some client elements that need changes directly from server side code.
  • PokeIn.Comet.BrowserHelper.SetElementEvent: You can listen to client side element events from the server side (very useful?)
    You can prepare the autocomplete controls easily with this method.

So, let me know about the articles on PokeIn library and/or Comet Ajax you want. ;)

History

  • 22nd April, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer (Senior) Pagos
Turkey Turkey
creating an application is a life style. not a job!

Comments and Discussions

 
GeneralThe application is not working with IIS6 (Win2003) and IIS7 (Win2008) Pin
Houssam Hamdan7-Jul-10 19:35
Houssam Hamdan7-Jul-10 19:35 
GeneralLong polling or http streaming Pin
Houssam Hamdan7-Jul-10 1:22
Houssam Hamdan7-Jul-10 1:22 
GeneralRe: Long polling or http streaming Pin
Oguz Bastemur7-Jul-10 12:08
Oguz Bastemur7-Jul-10 12:08 
QuestionThere is no timeout mechanism? Pin
dannykawai28-Jun-10 16:06
dannykawai28-Jun-10 16:06 
AnswerRe: There is no timeout mechanism? Pin
Oguz Bastemur1-Jul-10 12:47
Oguz Bastemur1-Jul-10 12:47 
GeneralThe PokeIn does not work in II7 Pin
Nereus_hou10-May-10 17:03
Nereus_hou10-May-10 17:03 
It works fine in debug mode. Please help to check. Thanks.
GeneralRe: The PokeIn does not work in II7 Pin
Oguz Bastemur11-May-10 4:37
Oguz Bastemur11-May-10 4:37 
GeneralThis Sample is not working in IIS 7 Pin
naveenIIT6-May-10 0:45
naveenIIT6-May-10 0:45 
GeneralRe: This Sample is not working in IIS 7 Pin
Oguz Bastemur11-May-10 4:38
Oguz Bastemur11-May-10 4:38 
GeneralRe: This Sample is not working in IIS 7 [modified] Pin
naveenIIT11-May-10 17:55
naveenIIT11-May-10 17:55 
GeneralRe: This Sample is not working in IIS 7 Pin
Oguz Bastemur12-May-10 2:22
Oguz Bastemur12-May-10 2:22 
GeneralRe: This Sample is not working in IIS 7 Pin
naveenIIT12-May-10 20:50
naveenIIT12-May-10 20:50 
GeneralRe: This Sample is not working in IIS 7 Pin
Oguz Bastemur1-Jul-10 12:49
Oguz Bastemur1-Jul-10 12:49 

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.