使用 WCF 和 MSMQ 的示例启动项目






4.88/5 (12投票s)
本项目作为一个入门应用程序,旨在帮助您开始使用 WCF 和 MSMQ。它使用了 MsmqIntegrationBinding。示例消息的结构借用了 Northwind 数据库,但该数据库不是必需的。
引言
作为我正在进行的一个项目的一部分,我被委派开发一个基于 Windows Communication Foundation (WCF) 的 Web 服务,作为 MSMQ 队列的前端。这是学习一项新技术的好机会,我渴望地寻找示例。
我最初的尝试非常令人沮丧。我在网上找到了一些示例,但就是无法让它们工作。术语令人费解。当我发现 Dennis van der Stelt 博客上一篇出色的入门项目时,我的进度大大加快。我极力向任何刚开始接触 WCF 的人推荐它。我终于在 MSDN 的“Windows Communication Foundation to Message Queuing”页面找到了一个演示如何使用 WCF 将消息提交到队列的示例。
我的经理建议将应用程序简化为只将 XML 消息排队,而不是对象(PurchaseOrder
),就像文章中所示的那样。这使得 WCF 服务可以充当一个通用的路由器,无需读取或解释消息在队列中的内容。本项目是我在 MSDN 示例的基础上创建的原型。我强烈建议希望开始学习 WCF 的读者除了查看本文附带的解决方案外,还要查看原始示例。
代码审查
我们从头开始,这样一开始就知道我们要去哪里。
上图显示了一个客户端应用程序,它已成功将 XML 文档作为字符串提交到一个 WCF 服务。这就是客户端所做的全部,即构建一个 XML 字符串并将其提交给服务。
WCF 服务的输出显示了两个组件的输出。前两行确认我们的 WCF 服务已启动并正在运行。其余行由监控消息队列的异步处理器输出。在这种情况下,它只是输出 MSMQ 消息标签的路由信息以及 XML 消息的内容。请注意,消息可以是任何有效的 XML 文档;处理器并不关心其内容。该处理器可以根据 MSMQ 消息标签中指定的目的地进行扩展,将消息传递到多个端点之一。如果这近似于您所需的功能,那么请继续阅读,我们将深入探讨实现此解决方案的代码。
客户端
客户端是一个创建 XML 消息的简单项目。我选择从磁盘文件读取消息的大纲。然后,我将我的示例数据与大纲合并。以下代码说明了这些操作。
//Line 1
string fileTemplate =
ConfigurationManager.AppSettings["ShipperTxnTemplate"];
fileDoc.Load(fileTemplate);
if (fileDoc.DocumentElement == null)
return;
string trnID = "00001001"; //Line 6
XmlNode rootNode = fileDoc.LastChild.LastChild.FirstChild;
rootNode.Attributes["txnid"].Value = trnID;
rootNode.Attributes["status"].Value = "Queued For Submission";
rootNode.Attributes["submitdate"].Value = DateTime.Now.ToString();
XmlNode fileNode = rootNode.FirstChild;
fileNode.Attributes["CompanyName"].Value = "FedEx Kinkos";
fileNode.Attributes["Phone"].Value = "425-884-9000";
上面代码片段中的第 1 行从客户端应用程序配置文件(app.config)中读取模板文件的位置。第 6-14 行将示例数据与大纲合并。现在消息已准备好发送到 WCF 服务。以下代码说明了这些操作。
string batchMsg = fileDoc.InnerXml; //Line 1
MessageProcessorClient strClient =
new MessageProcessorClient("MessageResponseEndpoint");
MsmqMessage<String> strXmlMsg = new MsmqMessage<string>(batchMsg); //Line 3
strXmlMsg.Label = "[WCFMQ_Client][WCFMQ_Service][ShipperTxn]";
using (TransactionScope scope =
new TransactionScope(TransactionScopeOption.Required))
{
strClient.SubmitStringMessage(strXmlMsg); //Line 7
scope.Complete();
}
上面代码片段中的第 1 行将 XMLDocument
对象转换为字符串。第 2 行根据客户端的 app.config 文件中的定义实例化一个 MessageProcessorClient
对象。以下代码片段是该定义的副本。
<endpoint name="MessageResponseEndpoint"
address="msmq.formatname:DIRECT=OS:.\private$\northwindqueue"
binding="msmqIntegrationBinding"
bindingConfiguration="MessageProcessorBinding"
contract="WCFMQService.IMessageProcessor">
</endpoint>
该定义包含了 WCF 消息的 ABC。一篇概述终结点定义的文章可以在这里找到。第 3 行实例化一个包含 XML 消息的 MsmqMessage
。第 4 行设置消息的标签。正是这个标签 WCF 可以用来识别目标服务和消息的类型。消息处理器不需要检查消息本身的内容。第 7 行将 MSMQ 消息分派给 WCF 服务。
WCF 服务
我希望您同意我的看法,即创建客户端很简单,创建服务则更容易。事实上,如果您使用的是 Visual Studio 2008,那么在创建服务或接收来自客户端的消息方面没有任何编码工作。让我们通过查看服务的 Main()
方法来确认这一点。
static void Main(string[] args)
{
//Line 1
if (!MessageQueue.Exists(ConfigurationManager.AppSettings["queueName"]))
MessageQueue.Create(ConfigurationManager.AppSettings["queueName"], true);
//Connect to the queue
MessageQueue Queue = new
MessageQueue(ConfigurationManager.AppSettings["queueName"]);
//Line 5
//Line 7
Queue.ReceiveCompleted += new ReceiveCompletedEventHandler(ProcessMessage);
Queue.BeginReceive(); //Line 8
Console.WriteLine("WCFMQService is running");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
}
第 1-2 行检查 MSMQ 队列是否存在,并在必要时创建它。队列的名称在服务应用程序配置文件(app.config)中定义。第 5 行创建队列的句柄,第 7 行将消息处理方法(ProcessMessage
)附加到队列。最后,第 8 行设置服务以监控队列中的消息。这些行中的每一行都与处理队列中的消息有关。正如我之前所说,在创建服务或接收来自客户端的消息方面没有编码工作。
注意:如果您注释掉第 8 行,则放入队列中的消息将保留在那里。取消注释并运行服务将导致处理并自动删除队列中的所有消息。您可以通过启动“计算机管理”(compmgmt.msc)实用程序,并在“服务和应用程序”节点下的“消息队列”子节点中检查名为“northwindqueue”的私有队列来查看队列的内容。
如果您找不到“消息队列”子节点,则可能尚未安装 MSMQ。您可以使用“添加/删除程序”来安装 MSMQ。您可以访问此MSDN 页面以获取有关安装 MSMQ 的说明。
最后,让我们看看我们解决方案的最后一部分——消息处理器。
// Connect to the queue.
MessageQueue Queue = (MessageQueue)source; //Line 2
Queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
// Pause the asynchronous receive operation while processing current message.
System.Messaging.Message msg = Queue.EndReceive(asyncResult.AsyncResult);
//Line 5
string[] tokenArr = msg.Label.Split(new char[] { '[', ']' }); //Line 7
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml((string)msg.Body);
Console.WriteLine(Environment.NewLine + "Processing incoming message "
+ Environment.NewLine + "Service Name:\t{0}"
+ Environment.NewLine + "Destination:\t{1}"
+ Environment.NewLine + "Document ID:\t{2}"
+ Environment.NewLine + "Message Contents:" +
Environment.NewLine + "{3}"
, tokenArr[1], tokenArr[3], tokenArr[5]
, FormatXML(xmlDoc.InnerXml, true));
//Resume servicing future messages
Queue.BeginReceive(); //Line 21
第 2 行创建队列的引用句柄。第 3 行创建一个格式化程序,使我们能够读取消息的内容。第 5 行在当前消息被处理时暂时暂停接收队列消息。第 7-18 行读取消息并将其输出到控制台。这是您可以在其中插入自定义代码以解释和处理收到的 XML 消息的代码点。第 21 行然后恢复监控队列以接收更多消息。注意:队列消息的处理是异步的,这是使用带 Windows 服务的队列的主要优势。将所有消息放入队列使服务能够立即返回以接受下一条消息,而无需等待上一条消息完全处理完毕。这可以为可伸缩性提供显著的优势。
摘要
Windows Communication Foundation 是一个用于应用程序之间互操作的优秀框架。您可以让多个应用程序通过队列交换消息。每个应用程序都可以将消息放入队列,并且可以根据消息上的标签读取目标为自己的消息。它们可以通过读取附加到每条消息的标签来实现这一点。或者,您可以创建一个专门的 WCF 路由器,将消息传递给一个或多个终结点。无论哪种方式,您都有一个优雅的方式来实现应用程序的服务导向架构。
参考文献
- Dennis van der Stelt 的博客
- MSDN 的“Windows Communication Foundation to Message Queuing”页面
- WCF 概述
- WCF 安装说明
历史
- 2009 年 1 月 3 日 - 初次提交。