使用 Visual C# 写入 Microsoft 消息队列并从中读取
本文介绍如何在 Visual C# 中 (MSMQ) 写入 Microsoft 消息队列并从中读取消息队列。
原始产品版本: Microsoft 消息队列
原始 KB 编号: 815811
在此任务中
摘要
本文介绍了以下内容:
- 如何在 Windows 应用程序中创建消息并将其发送到 MSMQ。
- 如何从专用队列中读取和反序列化要显示的消息内容。
要求
以下项目介绍了推荐的硬件、软件、网络基础结构、技能和知识以及所需的 Service Pack:
- 以下安装了 MSMQ 的操作系统之一, (它作为选项包含在四个操作系统) :Windows 2000 Professional (或 Server) ,或 Windows XP Professional (或 Server) 。
本文还假定你熟悉以下内容:
- MSMQ
- 使用命令提示符中的工具
写入 MSMQ 并从中读取
System.Messaging
.NET Framework中的命名空间包含必须从中读取和写入 MSMQ 的类。 若要创建一个模拟在线帐单支付系统的小型 Windows 应用程序,请执行以下步骤:
打开 Visual Studio .NET 或 Visual Studio 2005。
在 Visual C# 中创建新的 Windows 应用程序,然后将其命名为 MSMQ。
若要在未显示解决方案资源管理器时显示,请按 CTRL+ALT+L。 在“解决方案资源管理器”中,右键单击“引用”,然后单击“添加引用”。
在 “.NET ”选项卡上,选择 .dll 文件列表中的 System.Messaging.dll 文件。 单击 “选择”,然后单击“ 确定”。
注意
在 Visual Studio 2005 中,单击 DLL 列表中的 System.Messaging.dll 文件,然后单击“ 确定”。
Form1.cs 在“设计”视图中打开。 如果未打开,请双击解决方案资源管理器中的Form1.cs。
按 CTRL+Alt+X 打开工具箱。 在“工具箱”中,单击“Windows 窗体”选项卡。
从 “工具箱”中,将以下内容拖动到 Form1 的中间:
- 标签和文本框各有四行 (放置在每个标签) 的右侧。
- 在标签和文本框下,将两个按钮控件拖到 Form1 上。
右键单击控件,单击“ 属性”,然后将标签的 Text 属性设置为以下 (,以便) :
- 支付给:
- 您的姓名:
- 量:
- 截止日期:
在“ 属性 ”对话框中,将 button1 的 Text 属性设置为 “发送付款”,并将 button2 的 Text 属性设置为 “处理付款”。
此应用程序适用于必须首先在计算机管理控制台中创建的专用队列。 为此,请按照下列步骤操作:
- 在桌面上,右键单击“ 我的电脑”,然后单击“ 管理”。
- 展开“ 服务和应用程序” 节点以查找 MSMQ。
注意
如果未找到 MSMQ,则不会安装它。
展开 “消息队列”,右键单击“ 专用队列”,指向 “新建”,然后单击“ 专用队列”。
在“ 队列名称 ”框中,键入 billpay,然后单击“ 确定”。
注意
不要选中“事务检查”框。 使计算机管理控制台保持打开状态,因为稍后会返回到该控制台查看消息。
在 Form1 代码的顶部,在类声明前添加两个
USING
语句,以包括驻留在命名空间和System.Text
命名空间中的其他System.Messaging
类。 (命名空间System.Text
用于使用StringBuilder
类,它是在连接 strings 时最好使用的新.NET Framework类。)using System.Messaging; using System.Text;
创建一个结构,其中包含用于保存定义付款的数据的变量。 若要创建 结构,请在 Main 过程后面添加以下代码:
public struct Payment { public string Payor,Payee; public int Amount; public string DueDate; }
将以下步骤中的代码添加到
Click
的button1
事件。将 结构的属性设置为窗体元素的值,如下所示:
Payment myPayment; myPayment.Payor = textBox1.Text; myPayment.Payee = textBox2.Text; myPayment.Amount = Convert.ToInt32(textBox3.Text); myPayment.DueDate = textBox4.Text;
创建 类的
Message
实例,然后将 属性设置为Body
结构payment
:System.Messaging.Message msg = new System.Messaging.Message(); msg.Body=myPayment;
若要将消息发送到 MSMQ,请创建 类的
MessageQueue
实例并调用Send
传入Message
对象的方法。 类MessageQueue
是管理与 MSMQ 的交互的包装器。注意
用于设置在计算机管理控制台中创建的专用队列路径的语法。 专用队列采用 的形式
machinename\Private$\queuename
。 使用点或句点引用本地主机, (显示为 .) 。MessageQueue msgQ =new MessageQueue(".\\Private$\\billpay"); msgQ.Send(msg);
现在存在用于向 MSMQ 发送消息的代码。 .NET Framework使用
XMLMessageFormatter
对象自动序列化消息。 发送消息时隐式创建此对象。
将以下步骤中的代码添加到
Click
button2 的事件。 事件处理程序button2_Click
接收并处理事件处理程序中发送的button1
付款消息。第一行代码与第一个事件处理程序中的代码行相同:
MessageQueue msgQ = new MessageQueue(".\\Private$\\billpay");
创建要传递给
XMLMessageFormatter
类的类型数组。注意
接收消息时必须显式创建此类。 类的
XMLMessageFormatter
构造函数采用类型名称的字符串数组,或者更理想地采用Type
类型数组: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=((Payment)msgQ.Receive().Body);
这些类型指示
XMLMessageFormatter
如何反序列化消息。通过调用
Receive
方法接收消息。Body
访问 属性以读取消息内容。 属性Body
返回对象,因此必须将 对象强制转换为付款类型才能以可用形式检索内容:StringBuilder sb = new StringBuilder(); sb.Append("Payment paid to: " + myPayment.Payor); sb.Append("\n"); sb.Append("Paid by: " + myPayment.Payee); sb.Append("\n"); sb.Append("Amount: $" + myPayment.Amount.ToString()); sb.Append("\n"); sb.Append("Due Date: " + Convert.ToDateTime(myPayment.DueDate));
创建消息框以显示结果:
MessageBox.Show(sb.ToString(), "Message Received!");
完整的代码列表 (Form1.cs)
using System.Messaging;
using System.Text;
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace WindowsApplication1
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
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;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
// Required for Windows Form Designer support
InitializeComponent();
// TODO: Add any constructor code after InitializeComponent call
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
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 = new System.Drawing.Point(8, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(104, 32);
this.label1.TabIndex = 0;
this.label1.Text = "Pay To:";
// label2
this.label2.Location = new System.Drawing.Point(8, 80);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(104, 32);
this.label2.TabIndex = 1;
this.label2.Text = "Your Name:";
// label3
this.label3.Location = new System.Drawing.Point(8, 136);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(112, 32);
this.label3.TabIndex = 2;
this.label3.Text = "Amount:";
// label4
this.label4.Location = new System.Drawing.Point(8, 184);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(104, 40);
this.label4.TabIndex = 3;
this.label4.Text = "Due To:";
// textBox1
this.textBox1.Location = new System.Drawing.Point(152, 24);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(128, 20);
this.textBox1.TabIndex = 4;
this.textBox1.Text = "textBox1";
// textBox2
this.textBox2.Location = new System.Drawing.Point(160, 80);
this.textBox2.Name = "textBox2";
this.textBox2.TabIndex = 5;
this.textBox2.Text = "textBox2";
// textBox3
this.textBox3.Location = new System.Drawing.Point(160, 128);
this.textBox3.Name = "textBox3";
this.textBox3.Size = new System.Drawing.Size(112, 20);
this.textBox3.TabIndex = 6;
this.textBox3.Text = "textBox3";
// textBox4
this.textBox4.Location = new System.Drawing.Point(160, 184);
this.textBox4.Name = "textBox4";
this.textBox4.Size = new System.Drawing.Size(120, 20);
this.textBox4.TabIndex = 7;
this.textBox4.Text = "textBox4";
// button1
this.button1.Location = new System.Drawing.Point(8, 232);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(104, 40);
this.button1.TabIndex = 8;
this.button1.Text = "Send Payment";
this.button1.Click += new System.EventHandler(this.button1_Click);
// button2
this.button2.Location = new System.Drawing.Point(160, 232);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(120, 40);
this.button2.TabIndex = 9;
this.button2.Text = "Process Payment";
this.button2.Click += new System.EventHandler(this.button2_Click);
// Form1
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
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 = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
Payment myPayment;
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(".\\Private$\\billpay");
msgQ.Send(msg);
}
private void button2_Click(object sender, System.EventArgs e)
{
MessageQueue msgQ = new MessageQueue(".\\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=((Payment)msgQ.Receive().Body);
StringBuilder sb = new StringBuilder();
sb.Append("Payment paid to: " + myPayment.Payor);
sb.Append("\n");
sb.Append("Paid by: " + myPayment.Payee);
sb.Append("\n");
sb.Append("Amount: $" + myPayment.Amount.ToString());
sb.Append("\n");
sb.Append("Due Date: " + Convert.ToDateTime(myPayment.DueDate));
MessageBox.Show(sb.ToString(), "Message Received!");
}
public struct Payment
{
public string Payor,Payee;
public int Amount;
public string DueDate;
}
}
}
注意
应在 Visual Studio 2005 中更改代码。 创建Windows 窗体项目时,默认情况下,Visual C# 会向项目添加一个窗体。 此窗体名为 Form1。 表示窗体的两个文件名为 Form1.cs 和 Form1.designer.cs。 使用 Form1.cs 编写代码。 Designer.cs 文件是Windows 窗体 Designer写入实现通过添加控件执行的所有操作的代码的位置。 有关 Visual C# 2005 中Windows 窗体 Designer的详细信息,请参阅创建 Visual C# (项目 )
验证代码
在 “调试” 菜单上,单击“ 启动”。
在每个文本框中键入值,然后单击“ 发送付款”。
返回到计算机管理控制台。 单击 billpay 下的“专用队列”中的“队列邮件”文件夹,然后验证 MSMQ 是否收到了 (信封图标) 指示的消息。
右键单击邮件,单击“ 属性”,然后单击“ 正文 ”选项卡。你会注意到付款消息。
注意
付款消息的内容序列化为 XML。
返回到帐单支付 Windows 应用程序,然后单击“ 处理付款 ”按钮。 你将看到一个消息框,用于确认邮件的接收并显示该消息。
疑难解答
缺少专用队列通常仅在 Windows 2000 专业版和 Windows XP 专业版上是一个问题。 Windows 2000 Server 和 Windows XP Server 允许使用公共队列。
将正确的参数传递给
XMLMessageFormatter()
可能比较棘手。 在此示例中,如果对象或付款类型未包含在传递给构造函数的 Type 数组中,则会引发异常。