Click here to Skip to main content
15,884,388 members
Articles / Programming Languages / C#

Message queuing: A message notification system and a brief introduction

Rate me:
Please Sign up or sign in to vote.
2.20/5 (3 votes)
21 Aug 2007CPOL3 min read 24K   177   14   1
A simple application which can be a used for furture expansion and also an introcudtion to MSMQ.

Introduction

The article is about message queuing and a sample program which can be used as a Message Notification application.

Background

A task assigned to me in the company in which I work involved a program with the ability for checking messages of each user of an eOffice application. The most important features were the ability to reuse this program in similar cases, and having high performance as as not to interrupt other tasks while it had to check for new messages about every 30 seconds.

At first, I thought of a simple Windows Service, but when it came to adaptability with other main programs, I came up with an completely independent program that all huge applications like eOffice can be modified to use with a little configuration modifications.

Unfortunately, because of the company rules, I couldn't put the main source code here, but I wrote a sample app. I hope it be useful for you.

If you don't have know enough information about MSMQ, I suggest you read some great articles about it here in CodeProject and also MSDN.

It also provides you a notify icon with a balloon tool tip in .NET 2003. Though it is simple to do in .NET 2.0, it is not that easy to do it in .NET 2003!

Using the code

First, a Stored Procedure should provide you a table containing the columns ID and Name. IDs should be unique because they will be the unique names of your queues. I have arbitrarily converted my DataSet to a Hashtable because the Name column will be the label of the queues later, and I found it easier.

As it is a data access class, I made it a Singleton as there is no need to have more than one instance of it.

So you can have a Stored Procedure, or just a table with two columns will be enough here in this sample program. Write your own connection string in the conStr field.

C#
public class DataAccess
{
    private static DataAccess instance;
    protected DataAccess()
    {
    //
    // TODO: Add constructor logic here
    //
    }
    public static DataAccess Instance()
    {
        if (instance == null)
        {
            instance = new DataAccess();
        }
        return instance;
    }
    public Hashtable GetQueues(string command)
    {
        System.Data.DataSet ds = new DataSet();
        /////////TEST ,TEST, TEST /////////
        string conStr = "workstation id=SHABANI_A;packet size=4096;" + 
                        "integrated security=SSPI;data source=SHABANI_A;" + 
                        "persist security info=False;initial catalog=eOffice";
        /////////////////////////////////// 
        System.Data.SqlClient.SqlConnection sqlConnection = new SqlConnection(conStr);
        sqlConnection.Open();
        System.Data.SqlClient.SqlDataAdapter sqlDataAdapter = 
                     new SqlDataAdapter(command,sqlConnection);
        try
        {
            sqlDataAdapter.Fill(ds);
        }
        catch (Exception e)
        {
            string s = e.Message;
        }
        sqlConnection.Close();
        return convertor(ds);
    }
    private Hashtable convertor(DataSet myDataSet)
    {
        Hashtable ht = new Hashtable();
        foreach(DataRow myRow in myDataSet.Tables[0].Rows)
        {
            ht.Add(myRow[0],myRow[1]);
        }
        return ht;
    }
}

After passing the above, you will have a list of queries you need. To create the queries, you have two ways; I have used the programmatic one here as it is the only useful way for a programmer!

What the configuration class does is just give the server name, and you can just open the config.xml file and write you own computer name in front of the database server name. Actually, this will be useful when it is to be used in a network.

For this article, the only important method is CreateQueue(Hashtable IdAndName), which will receive the hashtable you built above and create the related queues.

C#
public class QueueDealer
{
    public QueueDealer()
    {
        //
        // TODO: Add constructor logic here
        //
    }
    #region create
    public void CreateQueue(Hashtable IdAndName)
    {
        try
        {
            Configuration conf = new Configuration();
            string machineName = conf.DBServerName().ToString();
            IDictionaryEnumerator myEnumerator =IdAndName.GetEnumerator();
            while ( myEnumerator.MoveNext() )
            {
                MessageQueue.Create(machineName + "\\" + myEnumerator.Key);
                MessageQueue mq = new MessageQueue(machineName + "\\" + myEnumerator.Key);
                mq.Label = myEnumerator.Value.ToString();
            }
        }
        catch (Exception e)
        {
            string p = e.Message;
        }
    }
    #endregion
    #region delete
    public void DeleteQueue(string queueName)
    {
        Configuration conf = new Configuration();
        string machineName = conf.DBServerName();
        if(MessageQueue.Exists(machineName +"\\" + queueName))
            MessageQueue.Delete (machineName +"\\" + queueName);
        }
    
    public void DeleteQueue(ArrayList queueNames)
    {
        Configuration conf = new Configuration();
        string machineName = conf.DBServerName();
        foreach (string name in queueNames)
            if(MessageQueue.Exists(machineName +"\\" + name))
                MessageQueue.Delete(machineName +"\\" + name);
    }
    #endregion
    #region clear
    public void ClearQueue(MessageQueue queue)
    {
        if(queue != null)
            queue.Purge();
        else throw new NullReferenceException("");
    }
    public void ClearQueue(ArrayList queues)
    {
        foreach (MessageQueue queue in queues)
            if(queue != null)
                queue.Purge();
            else throw new NullReferenceException("");
    }    
    #endregion          
}

Both the above parts should be done by the server in the main application, but here, you will do them just once as they are in order in the form. The server should give the required queue names and create them.

The MessageDealer class is used to send and receive messages.

Remember that objects should be serializable in order to be sent and received. The formatter specifies in which format you want your object to be sent..

Object is your message object. One of its fields is the number of messages and it may have an ArrayList including the messages.

C#
public class MessageDealer
{
    public MessageDealer()
    {
        //
        // TODO: Add constructor logic here
        //
    }
    #region send
        public void SendObject(string ID,Object obj)
    {
        
        try
        {    
            Configuration conf = new Configuration();
            string machineName = conf.DBServerName();
            MessageQueue mQ = new System.Messaging.MessageQueue(machineName + "\\" + ID);
            mQ.Formatter = new BinaryMessageFormatter();
            mQ.Send(obj);
        }
        catch(Exception e)
        {
        }
        
    }
    public void Send(string queuePath,object[] objs)
    {
        MessageQueue mQ = new System.Messaging.MessageQueue (queuePath);
        mQ.Formatter = new BinaryMessageFormatter();
        foreach(object obj in objs)
        mQ.Send(obj);
    }
    #endregion
    #region receive
    public Hashtable ReceiveMessages(MessageQueue[] MQ)
    {
        Hashtable MessageVsID = null;
        foreach(MessageQueue mq in MQ)
        {
            MessageQueue myQueue = new MessageQueue(mq.Path);
            myQueue.Formatter = new BinaryMessageFormatter();
            try
            {
                Message[] myMessages = myQueue.GetAllMessages();
                MessageVsID.Add(myQueue.QueueName,myMessages);
            }
            catch (MessageQueueException)
            {
                return null;
            }
            catch (InvalidOperationException e)
            {
                return null;
            }
        }
        return MessageVsID;
    }
    public System.Messaging.Message[] ReciveAllMessages(string ID)
    {
        Configuration conf = new Configuration();
        string machineName = conf.DBServerName();
        MessageQueue myQueue = new MessageQueue(machineName + "\\" + ID);
        return myQueue.GetAllMessages();
    }
    public Message ReciveMessage(string ID)
    {
            Configuration conf = new Configuration();
        string machineName = conf.DBServerName();
           MessageQueue myQueue = new MessageQueue(machineName + "\\" + ID);
        myQueue.MessageReadPropertyFilter.CorrelationId = true;
        Message returnMessage = null;
        myQueue.Formatter = new BinaryMessageFormatter();
        try
        {
            Message myMessage = myQueue.Receive(new TimeSpan(0,0,3));
                returnMessage = myMessage;
        }
        catch (MessageQueueException)
        {
            return null;
        }
        catch (InvalidOperationException e)
        {
            return null;
        }
        return returnMessage;
         
    }
    
    #endregion
        
}

Now, you should click the Receive Queue Info button:

C#
private void btnRecQueInfo_Click(object sender, System.EventArgs e)
{
    DataAccess ds = DataAccess.Instance();
    ht = ds.GetQueues("Select * from dbo.Queue ");
}

then the Create Queue button:

C#
private void btnCreQue_Click(object sender, System.EventArgs e)
{
    QueueDealer qd = new QueueDealer();
    qd.CreateQueue(ht);
}

After that, click Send Messages a couple of times. The Person object here is the same as the Message object I talked about, but I don't know way I named it Person!

C#
private void btnSendMessage_Click(object sender, System.EventArgs e)
{
    Random r = new Random(System.DateTime.Now.Second);
    Person p = new Person();
    p.ID = r.Next(7).ToString();
    ID = p.ID;
    p.p = r.Next(40).ToString();
    md.SendObject(p.ID,p);
}

Now after clicking the Start Receiving Messages button, every 5 seconds, your queues will be checked and you will be informed by the notify icon and its tool tip.

C#
private void btnStart_Click(object sender, System.EventArgs e)
{
    
    aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);
    // Set the Interval to 5 seconds.
    aTimer.Interval=5000;
    aTimer.Enabled=true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    try
    {
        Message m =  md.ReciveMessage(ID);
        per = m.Body as Person;
        this.notice("you have " + per.p.ToString() + " new messages");
    }
    catch(Exception ex)
    {
        string g = ex.Message.ToString();
    }
    
}
private void notice(string d)
{
    NotifyIcon.Rubbish2 r2 = new Rubbish2();
    r2.notice("Your messages",d);
}

You can keep clicking on the Send Message button while you are receiving, and you will see how it informs you about the messages.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
I Hate Programming But I Have To Come Up With It .

Comments and Discussions

 
GeneralI love to be notified of a forthcoming massage! Pin
Bartosz Bien21-Aug-07 7:47
Bartosz Bien21-Aug-07 7:47 

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.