Click here to Skip to main content
15,893,487 members
Articles / Programming Languages / C#

A beginner's guide to queuing with WCF and MSMQ showing bi-directional client correspondance

Rate me:
Please Sign up or sign in to vote.
4.92/5 (9 votes)
2 Jan 2013CPOL24 min read 95.7K   3.3K   38  
This is a working example of clients in queued correspondence with a service, sending messages to it, recieving unsolicited messages from it while both client and service can queue messages to the other while the other is offline.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Description; // For ServiceEndpoint
using System.Messaging;
using System.Transactions;
using GPH_QueuedMessageClient.ServiceReference1;
using System.Configuration; //Access app.config
using NGPH_InboundMessageContract;

namespace GPH_QueuedMessageClient
{
    public partial class MessageForm : Form
    {
        private static ServiceReference1.GPH_QueuedServiceClient m_Proxy;
        private static string m_queueName;
        public MessageForm()
        {
            InitializeComponent();
            
            m_Proxy = new ServiceReference1.GPH_QueuedServiceClient();

            
        }


        private void btnJoin_Click(object sender, EventArgs e)
        {
            // Create a queue here to recieve messages 
            m_queueName = ConfigurationManager.AppSettings["m_queueName"] + txtUsername.Text;
            // Create the transacted MSMQ queue if necessary
            if (!MessageQueue.Exists(m_queueName))
                MessageQueue.Create(m_queueName, true);//Creates a transactional queue.
            NetMsmqBinding Binding;
            Binding = new NetMsmqBinding();
            Binding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None;
            Binding.Security.Transport.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None;
           
            string baseAddress = ConfigurationManager.AppSettings["baseAddress"];
            baseAddress += txtUsername.Text;
            string endpointAddressRoot = ConfigurationManager.AppSettings["endpointAddressRoot"];
            string strEndpointAddress = endpointAddressRoot + txtUsername.Text;
            // Open a client side service for that queue
            EndpointAddress address = new EndpointAddress(strEndpointAddress);
            //ServiceEndpoint endpoint = new ServiceMetadataEndpoint(address);// Use this to programatically add the address with 
                                                                              // binding and contract still comming from the config
                                                                              // This is a .NET 4.0 feature
                                                                              // Otherwise AddServiceEndpoint requires all three!
            // The host that will take in the responses is created at runtime to include the name of the
            // user just entered in the endpoint.
            ServiceHost host = new ServiceHost(typeof(CGPH_InboundMessageHandler), new Uri(baseAddress));
            CGPH_InboundMessageHandler.RegistrationEvent
               += new EventHandler<CGPH_InboundMessageHandler.RegistrationEventArgs>(CGPH_InboundMessageHandler_RegistrationEvent);
            CGPH_InboundMessageHandler.ShowMessageEvent
               += new EventHandler<CGPH_InboundMessageHandler.ShowMessageEventArgs>(CGPH_InboundMessageHandler_ShowMessageEvent);
            try
            {
                host.AddServiceEndpoint(typeof(IGPH_InboundMessageHandler), Binding, strEndpointAddress);
                host.Open();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message,"Exception opening host:" );
                MessageBox.Show(Ex.InnerException.Message, "Inner Exception:");
            }

            PublishToDataContract PublishTo;

            // Attach return address etc to the outbound message (Data contract)

            //LOWY - Appendix B
            PublishTo = new PublishToDataContract();
            PublishTo.PublishToAddress = strEndpointAddress;
            MessageHeader<PublishToDataContract> numberHeader = new MessageHeader<PublishToDataContract>(PublishTo);
           
            // Control scope via 'Using'
             using (OperationContextScope contextScope = new OperationContextScope(m_Proxy.InnerChannel))
            {
                try
                {
                    OperationContext.Current.OutgoingMessageHeaders.Add(
                        numberHeader.GetUntypedHeader("PublishToDataContract", "NGPH_QueuedMessageContract"));
                }
                catch (Exception Ex)
                {
                    MessageBox.Show("Exception: {0}", Ex.Message);
                }
                m_Proxy.RegisterUser(txtUsername.Text);
            }

             // change the button states
             this.btnJoin.Enabled = false;
             this.btnSend.Enabled = true;
             this.btnLeave.Enabled = true;
             this.txtMessageOutbound.Enabled = true;
        }

        private void CGPH_InboundMessageHandler_RegistrationEvent(object sender, CGPH_InboundMessageHandler.RegistrationEventArgs e)
        {

            //txtMessageLog.Text = ("Subscriber Count = " + NGPH_InboundMessageContract.CGPH_InboundMessageHandler.m_SubscriberList.Count().ToString());

            clstSubscriber.Items.Clear();
            clstSubscriber.Items.Clear();

            foreach (string subscriber in NGPH_InboundMessageContract.CGPH_InboundMessageHandler.m_SubscriberList)
                clstSubscriber.Items.Add(subscriber);
        }
        private void CGPH_InboundMessageHandler_ShowMessageEvent(object sender, CGPH_InboundMessageHandler.ShowMessageEventArgs e)
        {
            // Prep the new message for appearance in the inbox
            string tmpStr = String.Format("[{0}]: {1} at [{2}]",
                CGPH_InboundMessageHandler.m_FromUser.ToUpper(),
                CGPH_InboundMessageHandler.m_MessageRecieved, 
                DateTime.Now.ToShortTimeString());
            // format the inbox.
            //If the current length is > 0 create a format pattern to include a carriage return / linefeed 
            //between the existing content and the new content
            string format = this.txtMessageLog.Text.Length > 0 ? "{0}\r\n{1}" : "{0}{1}";

            // use the format pattern to append the new message to the inbox
            this.txtMessageLog.Text = String.Format(format, this.txtMessageLog.Text, tmpStr);
            this.txtMessageLog.SelectionStart = this.txtMessageLog.Text.Length - 1;
            this.txtMessageLog.ScrollToCaret();

        }
        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void MessageForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            m_Proxy.Close();

        }

        private void MessageForm_Load(object sender, EventArgs e)
        {
            // Initialize the fields / buttons
            this.btnJoin.Enabled = false;
            this.btnSend.Enabled = false;
            this.btnLeave.Enabled = false;
            this.btnExit.Enabled = true;
            this.txtMessageOutbound.Enabled = false;

            // Initial eventhandlers
            this.txtUsername.TextChanged += new EventHandler(txtUsername_TextChanged);
            this.FormClosing += new FormClosingEventHandler(MessageForm_FormClosing);

        }

        private void txtUsername_TextChanged(object sender, EventArgs e)
        {
            if (this.txtUsername.Text != String.Empty)
            {
                this.btnJoin.Enabled = true;
            }


        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            string[] addressList = new string[clstSubscriber.CheckedItems.Count];
            int i = 0;
            //            MessageBox.Show("Starting foreach", "Debug");
            for (int j = 0; j < clstSubscriber.CheckedItems.Count; j++)
            {
                //                MessageBox.Show(string.Format("Adding {0} - {1}", i.ToString(), clstSubscriber.CheckedItems[j]), "Debug");
                addressList[i++] = (string)clstSubscriber.CheckedItems[j];
            }
            //            MessageBox.Show("Forward the message to the service", "Debug");
            // Forward the message to the service - but only where there are recipients)
            if (addressList.Count() > 0)
            {
                txtMessageOutbound.Enabled = false;
                m_Proxy.ReceiveMessage(this.txtUsername.Text, addressList, this.txtMessageOutbound.Text);
                txtMessageOutbound.Clear();
                txtMessageOutbound.Enabled = true;
            }
            else
            {
                MessageBox.Show("Please tick at least one recipient", "Message not addressed");
            }

        }

        private void btnLeave_Click(object sender, EventArgs e)
        {
            m_Proxy.RemoveUser(this.txtUsername.Text);
            this.btnJoin.Enabled = false;
            this.btnSend.Enabled = false;
            this.btnLeave.Enabled = false;
            this.btnExit.Enabled = true;
            this.txtMessageOutbound.Enabled = false;
            if (MessageQueue.Exists(m_queueName))
                MessageQueue.Delete(m_queueName);
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer
Ireland Ireland
My first program was written in Basic on a Sinclair Spectrum ZX 16K in the summer of '85. Having studied Computer Systems I attempted to break into the world of C but took a wrong turn and got immersed in COBOL!

I looked a C again in 1994 but didnt follow up on it. In 2001 I introduced myself to Visual C++ 6.0 courtesy of Ivor Hortons book, but found the going difficult. I tipped my toe in the .NET water in '05 but the first example I tried in VC++ 2005 express didnt work and allied with the absence of MFC in the express package, I parked that up.

Along the way my career got shunted into software testing

A personal machine change force me to migrate to VS2008 in 2008. The new edition of Ivor Hortons book for VC++ in VS2008 reintroduced me to .NET and I got curious whereupon I went out and acquired Stephen Fraser's "Pro Visual C++/CLI and
the .NET 3.5 Platform". I was hooked!

After 20 years I think I finally found my destination.

But it would take a further 8 years of exile before I was reappointed to a developer role. In that time I migrated to C# and used selenium wedriver (courtesy of Arun Motoori's Selenium By Arun) as the catalyst to finally grab the opportunity.

Comments and Discussions