Requirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:One of the following operating systems with Message Queuing installed (Message Queuing is included with the operating systems as an option):- Microsoft Windows 2000 Professional or Microsoft Windows 2000 Server
- Microsoft Windows XP Professional
- Microsoft Windows Server 2003
- Microsoft Message Queuing
- Using tools from the command prompt
Write to and Read from Message Queuing
The System.Messaging namespace in the .NET Framework has the classes that you must read from and write to Message Queuing. To create a small Windows application that mimics an online bill payment system, follow these steps:- Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.
- On the File menu, point to New, and then click Project.
- Click Visual C++ Projects under
Project Types, and then click Windows Form
Application under Templates.
Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Form Application under Templates. - Name the project MSMQ.
- In Solution Explorer, right-click
References, and then click Add
Reference.
Note In Solution Explorer, right-click MSMQ, click References, and then click Add New Reference. - On the .NET tab, click System.Messaging.dll file from the list of .dll files. Click Select, and then click OK.
- In Solution Explorer, double-click Form1.h(design).
- Press the CTRL+ALT+X key combination to open the toolbox. Click the Windows Forms tab.
- Add the following to the middle of Form1.h (design):
- 4 rows each of a Label and a Textbox (positioned to the right of each label).
- Under the labels and text boxes, add two Button controls to Form1.h (design).
- Right-click the controls, click
Properties, and then set the Text property
for the labels to the following (in order):
- Pay To:
- Your Name:
- Amount:
- Due Date:
- In the Properties dialog box, set the Text property of the button1 control to Send Payment, and then set the Text property of the button2 control to Process Payment.
- This application works with a private queue that you must
first create in the Computer Management console. To do this, follow these
steps:
- On the desktop, right-click My Computer, and then click Manage.
- Expand Services and Applications to
find Message Queuing.
Note You may not find the Messaging Queuing, when it is not installed. - Expand Message Queuing, right-click Private Queues, point to New, and then click Private Queue.
- In the Queue name text box, type
billpay, and then click OK.
Note Click to clear the Transactional check box. Leave the Computer Management console open for viewing messages.
- At the top of the code in the Form1.h file, add two USING
NAMESPACE statements before the class declaration to include the additional
classes that reside in the System::Messaging namespace and the System::Text namespace. (The StringBuilder class, a new .NET Framework class that it is best to use when you
concatenate strings, uses the System.Text namespace.)
using namespace System::Messaging; using namespace System::Text;
- Create a structure that contains variables to hold the data
that defines a payment. To create the structure, add the following code above
the declaration of the Form1 class::
__gc public struct Payment { System::String __gc* Payor; System::String __gc* Payee; int Amount; System::String __gc* DueDate; };
- Add the code in the following steps to the
Click event of button1:
- Set the properties of the structure to values of the
form elements as follows:
Payment* myPayment = new Payment; myPayment->Payor = textBox1->Text; myPayment->Payee = textBox2->Text; myPayment->Amount = Convert::ToInt32(textBox3->Text); myPayment->DueDate = textBox4->Text;
- Create an instance of the Message class, and then set the Body property to the payment structure:
System::Messaging::Message *msg = new System::Messaging::Message(); msg->Body=myPayment;
- To send a message to Message Queuing, create an
instance of the MessageQueue class and call the Send method that passes in the Message object. The MessageQueue class is the wrapper that manages the interaction with Message
Queuing.
Notice the syntax for setting the path of the private queue that you created in the Computer Management console. Private queues take the following form:computername\Private$\queuenameLocal host computers are referenced with a dot or a period ( ".") as follows:MessageQueue *msgQ =new MessageQueue(S".\\Private$\\billpay"); msgQ->Send(msg);
The code now exists to send a message to Microsoft Message Queuing. The .NET Framework automatically serializes the message by using an XMLMessageFormatter object. This object is implicitly created when messages are sent.
- Set the properties of the structure to values of the
form elements as follows:
- Add the following code to the Click event of the button2 control. The button2_Click event handler receives and processes the payment message that is
sent in the button1 event handler.
- The first line of code is the same as the line of code
that is in the first event handler:
MessageQueue *msgQ = new MessageQueue(S".\\Private$\\billpay");
- Create an array of types to pass to the XMLMessageFormatter class.
Note This class must be explicitly created when receiving messages. The constructor of the XMLMessageFormatter class takes either a string array of type names or, more preferably, a Type array of types:These types tell the XMLMessageFormatter how to deserialize the message.Payment *myPayment=new Payment(); Object *o=new Object(); System::Type *arrTypes[] = new System::Type* [2] ; arrTypes[0] = myPayment->GetType(); arrTypes[1] = o->GetType(); msgQ->Formatter = new XmlMessageFormatter(arrTypes); myPayment= static_cast<Payment*>(msgQ->Receive()->Body);
- Messages are received by calling the Receive method. Access the Body property to read the message contents. The Body property returns an object. Therefore, the object is cast to the
payment type to retrieve the contents in a usable form:
StringBuilder *sb = new StringBuilder(); sb->Append(S"Payment paid to: "); sb->Append(myPayment->Payor); sb->Append(S"\n"); sb->Append(S"Paid by: "); sb->Append(myPayment->Payee); sb->Append(S"\n"); sb->Append(S"Amount: $"); sb->Append(myPayment->Amount.ToString()); sb->Append(S"\n"); sb->Append(S"Due Date: "); sb->Append(Convert::ToString(Convert::ToDateTime(myPayment->DueDate)));
- Create a message box to display the results:
MessageBox::Show(sb->ToString(), S"Message Received!");
- The first line of code is the same as the line of code
that is in the first event handler:
Complete Code Listing (msmq.h)
#pragma once
using namespace System::Messaging;
using namespace System::Text;
namespace MSMQ
{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
__gc public struct Payment
{
System::String __gc* Payor;
System::String __gc* Payee;
int Amount;
System::String __gc* DueDate;
};
/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you must change the
/// 'Resource File Name' property for the managed resource compiler tool
/// that is associated with all .resx files that this class depends on. Otherwise,
/// the designers cannot interact correctly with localized
/// resources that are associated with this form.
/// </summary>
public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private: System::Windows::Forms::Label * label1;
private: System::Windows::Forms::Label * label2;
private: System::Windows::Forms::Label * label3;
private: System::Windows::Forms::Label * label4;
private: System::Windows::Forms::TextBox * textBox1;
private: System::Windows::Forms::TextBox * textBox2;
private: System::Windows::Forms::TextBox * textBox3;
private: System::Windows::Forms::TextBox * textBox4;
private: System::Windows::Forms::Button * button1;
private: System::Windows::Forms::Button * button2;
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container * components;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->label1 = new System::Windows::Forms::Label();
this->label2 = new System::Windows::Forms::Label();
this->label3 = new System::Windows::Forms::Label();
this->label4 = new System::Windows::Forms::Label();
this->textBox1 = new System::Windows::Forms::TextBox();
this->textBox2 = new System::Windows::Forms::TextBox();
this->textBox3 = new System::Windows::Forms::TextBox();
this->textBox4 = new System::Windows::Forms::TextBox();
this->button1 = new System::Windows::Forms::Button();
this->button2 = new System::Windows::Forms::Button();
this->SuspendLayout();
//
// label1
//
this->label1->Location = System::Drawing::Point(16, 32);
this->label1->Name = S"label1";
this->label1->TabIndex = 0;
this->label1->Text = S"Pay To:";
//
// label2
//
this->label2->Location = System::Drawing::Point(16, 72);
this->label2->Name = S"label2";
this->label2->TabIndex = 1;
this->label2->Text = S"Your Name:";
//
// label3
//
this->label3->Location = System::Drawing::Point(16, 112);
this->label3->Name = S"label3";
this->label3->TabIndex = 2;
this->label3->Text = S"Amount:";
//
// label4
//
this->label4->Location = System::Drawing::Point(16, 152);
this->label4->Name = S"label4";
this->label4->TabIndex = 3;
this->label4->Text = S"Due Date:";
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(136, 32);
this->textBox1->Name = S"textBox1";
this->textBox1->TabIndex = 4;
this->textBox1->Text = S"ABC";
//
// textBox2
//
this->textBox2->Location = System::Drawing::Point(136, 72);
this->textBox2->Name = S"textBox2";
this->textBox2->TabIndex = 5;
this->textBox2->Text = S"DEF";
//
// textBox3
//
this->textBox3->Location = System::Drawing::Point(136, 112);
this->textBox3->Name = S"textBox3";
this->textBox3->TabIndex = 6;
this->textBox3->Text = S"12";
//
// textBox4
//
this->textBox4->Location = System::Drawing::Point(136, 152);
this->textBox4->Name = S"textBox4";
this->textBox4->TabIndex = 7;
this->textBox4->Text = S"9/9/2003";
//
// button1
//
this->button1->Location = System::Drawing::Point(24, 208);
this->button1->Name = S"button1";
this->button1->Size = System::Drawing::Size(88, 23);
this->button1->TabIndex = 8;
this->button1->Text = S"Send Payment";
this->button1->Click += new System::EventHandler(this, button1_Click);
//
// button2
//
this->button2->Location = System::Drawing::Point(152, 208);
this->button2->Name = S"button2";
this->button2->Size = System::Drawing::Size(104, 23);
this->button2->TabIndex = 9;
this->button2->Text = S"Process Payment";
this->button2->Click += new System::EventHandler(this, button2_Click);
//
// Form1
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(292, 266);
this->Controls->Add(this->button2);
this->Controls->Add(this->button1);
this->Controls->Add(this->textBox4);
this->Controls->Add(this->textBox3);
this->Controls->Add(this->textBox2);
this->Controls->Add(this->textBox1);
this->Controls->Add(this->label4);
this->Controls->Add(this->label3);
this->Controls->Add(this->label2);
this->Controls->Add(this->label1);
this->Name = S"Form1";
this->Text = S"Form1";
this->ResumeLayout(false);
}
private: System::Void button1_Click(System::Object * sender, System::EventArgs * e)
{
try
{
Payment* myPayment = new Payment;
myPayment->Payor = textBox1->Text;
myPayment->Payee = textBox2->Text;
myPayment->Amount = Convert::ToInt32(textBox3->Text);
myPayment->DueDate = textBox4->Text;
System::Messaging::Message *msg = new System::Messaging::Message();
msg->Body=myPayment;
MessageQueue *msgQ =new MessageQueue(S".\\Private$\\billpay");
msgQ->Send(msg);
}
catch(Exception *e)
{
MessageBox::Show(e->Message);
}
}
private: System::Void button2_Click(System::Object * sender, System::EventArgs * e)
{
try
{
MessageQueue *msgQ = new MessageQueue(S".\\Private$\\billpay");
Payment *myPayment=new Payment();
Object *o=new Object();
System::Type *arrTypes[] = new System::Type* [2] ;
arrTypes[0] = myPayment->GetType();
arrTypes[1] = o->GetType();
msgQ->Formatter = new XmlMessageFormatter(arrTypes);
myPayment= static_cast<Payment*>(msgQ->Receive()->Body);
StringBuilder *sb = new StringBuilder();
sb->Append(S"Payment paid to: ");
sb->Append(myPayment->Payor);
sb->Append(S"\n");
sb->Append(S"Paid by: ");
sb->Append(myPayment->Payee);
sb->Append(S"\n");
sb->Append(S"Amount: $");
sb->Append(myPayment->Amount.ToString());
sb->Append(S"\n");
sb->Append(S"Due Date: ");
sb->Append(Convert::ToString(Convert::ToDateTime(myPayment->DueDate)));
MessageBox::Show(sb->ToString(), S"Message Received!");
}
catch(Exception *e)
{
MessageBox::Show(e->Message);
}
}
};
}
- Click Project, and then click
<ProjectName>
Properties.
Note <ProjectName> is a placeholder for the name of the project. - Expand Configuration Properties, and then click General.
- Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.
/clr (Common Language Runtime Compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx
Verify the Code
- On the Debug menu, click Start.
- Type values in each text box, and then click Send Payment.
- Return to the Computer Management console. In Private Queues under billpay, click the Queue messages folder, and then verify that Message Queuing received a message. An envelope icon indicates a new message.
- Right-click the message, click Properties,
and then click the Body tab. You notice the payment
message.
Note The contents of the payment message are serialized as XML. - Return to the bill payment Windows application, and then click Process Payment. You receive a message box that confirms the receipt of a message and that displays the message.
Troubleshooting
- The lack of a private queue is generally an issue only on computers that are running Windows 2000 Professional or Windows XP Professional. Windows 2000 Server and Windows Server 2003 permit the use of the public queue.
- Passing the correct arguments to XMLMessageFormatter() can be tricky. In this example, exceptions are thrown if either the object or the Payment Types are not included in the Type array that is passed to the constructor.