Secured Intranet Messenger using MSMQ in C#

Introduction

Up to now I have seen so many samples on using MSMQ (Microsoft Message Queuing Service) with .NET. But, I haven't seen a real-time sample which will help us in daily work. The main reason to design this intranet messenger is that, there is monitoring of intranet messages in my company. So, I thought to design an application which can't be tracked by anyone. This application will allow you to send, receive, store intranet messages even when you are not running this application or even System also. Before explaining how to design this application, I will discuss the things I used in designing this. Later, I will explain little bit about the uses of it than followed by design.

What is MSMQ?

Microsoft Message Queuing is Microsoft technology for asynchronous messaging. Whenever there is need for applications to send messages to each other, MSMQ can be used. MSMQ can communicate between remote machines, even over internet using http/https. It's free and comes with Windows, but is not installed by default. In order to integrate this in .NET, Microsoft provided a wrapper on this COM component for ease of use. So, we can use this technology to pass messages (instant) between intranet users.

This application is designed in VS.NET 2003 in C# using Windows Forms. Some of the silent features of this application are.

  • Allows us to send message to any intranet system having MSMQ installed on it.
  • Allows us to receive message from any intranet system.
  • Allows us to store the conversation in a text file for further reference.
  • Allows us to show messages, which are received when application or system is shut downed.
  • Show exact sent and received timings of messages.
  • It is secured, no one can keep track of your messages.

Than coming to design, Create a new windows Application in VS 2003 using C# Language and design forms as shown below.

Image1.gif

This is the startup window for the application. Add all controls as shown in figure above. I will explain first about the functionality of all controls present on the form.

  • Add New User menu item will call a new form, where we can add a contact name and corresponding machine name and save it in xml file.
  • Chat menu item will open a new chat window for selected contact.
  • View history will load the selected contact's history in a new window.
  • Exit will close entire application.
  • Unread messages textbox will show the messages which are arrived when the application or system is not running.
  • Public Queue combobox will load all queues that are available to you.
  • Contact to Chat combobox will load all conacts, which are saved in xml file using Add New User Window.

Than design adduser form as shown below.

Image2.gif

What I done here is, just I saved all entered contactname and his corresponding machine name in an xml file.

Next, create chat window form as shown below.

Image3.gif

Here, we are going to send and receive messages from the Queue. I will just outline the functionality of the controls on the form.

  • Send button or menuitem will send the message to selected contact.
  • Receive button or meuitem will receive messages from all contacts.
  • Save History will save message history in a text file.
  • Auto Monitor will keep on monitoring message queue for new incoming messages.
  • Exit will close the chat window

Than finally design the form to display message history of a particular contact.

Image4.gif

In this form, there is no much logic. Just, I am displaying contents (message history) of selected contact in a multiline textbox.

Outline of the Messenger functionality

We are going to send message to selected user queue with message body and label as sent time and source m/c (m/c name of sending message).Than, we will unwrap and show message body and sent time. A timer is used to keep on monitoring for new incoming messages (queuemsgs Queue) and display it.

Now, I will explain main functionality present in the Messenger application in form wise.

Functionality of Main (startup) Form

OnLoad of Main form, first I am checking whether MSMQ is installed or not on your machine. Than, I am loading all public queues, creating an xml file for saving contacts details (contactname, machinename) and binding it to a combobox followed by loading of unread messages into a read-only textbox. These are the variables I declared in main form, which are going to be used in all forms

#region User-defined and Changed Variables

public System.Windows.Forms.ComboBox drpUsersList;
public frmadduser obj1;

public static Form1 frmMain;
public static chatwindow chatwin;
public static historywindow historywin;

public static string filename, selectedContact, selectedMCName;

#endregion

The code present in form_load of Startup form is

// To create a Message Queue if it doesn't exist...
try
{
    if (!MessageQueue.Exists(@".\queuemsgs"))
    {
        MessageQueue.Create(@".\queuemsgs", false);
        MessageBox.Show("Queue named queuemsgs is created on your machine");
    }
}
catch (InvalidOperationException ex)
{
    MessageBox.Show("Message Queuing has not been installed on this computer. Please install it by going to Control Panel -> Add/Remove Programs -> Add Windows Components and select Message Queuing and start this application...");
    System.Diagnostics.EventLog.WriteEntry("DOTNET Messenger Error", ex.Message + "::" + ex.StackTrace);
    Application.Exit();
    return;
}

// To load all public queues...
try
{
    MessageQueue[] queues = MessageQueue.GetPublicQueues();
    foreach (MessageQueue queue in MessageQueue.GetPublicQueues())
    {
        drppublicqueues.Items.Add(queue.Path);
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

// To create an XML file for storing contact details entered using AddNewUser window and bind it to a combobox...
try
{
    filename = @"c:\contactslist.xml";
    if (!File.Exists(filename))
    {
        File.Create(filename).Close();
        StreamWriter writer = new StreamWriter(filename);
        writer.Write("<?xml version=\"1.0\"?>");
        writer.Write("<users>");
        writer.Write("</users>");
        writer.Close();
        return;
    }
    else
    {
        DataSet ds = new DataSet();
        StreamReader reader = new StreamReader(filename);
        string tmpfilecontents = reader.ReadToEnd();
        reader.Close();
        if (tmpfilecontents.IndexOf("<machinename>") != -1)
        {
            ds.ReadXml(filename);
            drpuserslist.DataSource = ds.Tables[0];
            drpuserslist.DisplayMember = "name";
            drpuserslist.ValueMember = "machinename";
        }
    }
}
catch { }

// To load all unread messages...
try
{
    string queuepath = "";
    queuepath = @"FormatName:DIRECT=OS:" + System.Environment.MachineName + @"\queuemsgs";
    lblunread.Text = "Unread Messages in Queue " + System.Environment.MachineName + @"\queuemsgs";
    MessageQueue tmpqueue = new MessageQueue(queuepath);
    Type[] target = new Type[1];
    target[0] = typeof(string);
    foreach (System.Messaging.Message msg in tmpqueue.GetAllMessages())
    {
        msg.Formatter = new System.Messaging.XmlMessageFormatter(target);
        txtprevmsgs.Text += msg.Body.ToString() + " Received from " + msg.Label.ToString().Substring(msg.Label.ToString().LastIndexOf(":::") + 3) + " at " + msg.Label.ToString().Substring(0, msg.Label.ToString().LastIndexOf(":::")) + "\r\n";
    }
}
catch (Exception ex)
{
    System.Diagnostics.EventLog.WriteEntry("DOTNET Messenger Error", ex.Message + "::" + ex.StackTrace);
}

Remaining code for this form is available in the attachment.

Functionality of Chat Window

I am using Send_QueueMessages() and Get_QueueMessages() to send, receive messages from the queue and display it.

The code for Get_QueueMessages() is.

try
{
    msgqueue.Path = @"FormatName:DIRECT=OS:" + System.Environment.MachineName.ToString() + @"\queuemsgs";
    
    Type[] target = new Type[1];
    target[0] = typeof(string);
    
    System.Messaging.Message msg = msgqueue.Receive(new TimeSpan(0, 0, 2));
    msg.Formatter = new System.Messaging.XmlMessageFormatter(target);
    
    txtallmsgs.Text += "\r\n" + "HE/SHE says:" + "\r\n" + (msg.Body.ToString());
    
    if (msg.Label.ToString().Substring(msg.Label.ToString().LastIndexOf(":::") + 3) == Form1.selectedmcname.ToString())
    {
        lblreceived.Text = "Last message received at: " + msg.Label.ToString().Substring(0, msg.Label.ToString().LastIndexOf(":::"));
    }
    else
    {
        txtallmsgs.Text += " Received from " + msg.Label.ToString().Substring(msg.Label.ToString().LastIndexOf(":::") + 3) + " at " + msg.Label.ToString().Substring(0, msg.Label.ToString().LastIndexOf(":::")) + "\r\n";
    }
}
catch (Exception ex)
{
    if (ex.Message != "Timeout for the requested operation has expired.")
    {
        MessageBox.Show(ex.Message, "DOTNET Messenger Error");
    }
}

This method will set queue path and formatter to get message. Than, it will extract received message's body and label. Finally, it will check source m/c of message and displays its name, if chat window opened is not belonging to selected user else it will display just message and its sent time.

The code for Send_QueueMessages().

try
{
    string queuepath = "";

    if (Form1.selectedconact != "")
    {
        queuepath = @"FormatName:DIRECT=OS:" + Form1.selectedmcname.ToString() + @"\queuemsgs";
    }
    else
    {
        queuepath = @"FormatName:DIRECT=OS:" + Form1.selectedmcname;
    }

    msgqueue.Path = queuepath;
    msgqueue.Send(txtsentmsg.Text, DateTime.Now.ToLongTimeString() + ":::" + System.Environment.MachineName);

    txtallmsgs.Text += "\r\n" + "You Said :" + "\r\n" + txtsentmsg.Text;
    txtsentmsg.Text = "";

    lblsenttime.Text = "Last message sent at: " + DateTime.Now.ToLongTimeString();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message, "DOTNET Messenger Error");
    System.Diagnostics.EventLog.WriteEntry("DOTNET Messenger Error", ex.Message + "::" + ex.StackTrace);
}

This code will set destination's queue path and send message along with time of sending, m/c name and message body.

If Auto Monitor menuitem is checked, than a timer will check message queue for every 3 seconds for new messages and displays it in chat window without manually clicking on receive button.

Finally, history window will load the selected contact's history, which is stored in a text file.

On Form_load, It will open selected contact's history file and load it into a textbox.

try
{
    System.IO.StreamReader reader = new System.IO.StreamReader(@"C:\" + Form1.selectedconact + ".xml");
    textBox1.Text = reader.ReadToEnd();
    reader.Close();
    textBox1.SelectionStart = 0;
    textBox1.SelectionLength = 0;
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

So, by using few lines of code we can design our own messenger to chat with others present in the intranet. We can enhance this application further by adding functionality like mailing message history, good UI for displaying contacts.

I hope by using this messenger, from now onwards atleast few people can chat with other colleagues without bothering of message monitoring.

I am attaching source code for further reference. I hope this code will be useful for all.


Similar Articles