本示例演示如何在 Windows 进程激活服务 (WAS) 中承载从消息队列读取的应用程序。本示例使用 netMsmqBinding 并基于双向通信示例。本示例中的服务是一个 Web 承载的应用程序,而客户端是自承载的,并输出到控制台以观察提交的采购订单的状态。
提示
本主题的最后介绍了此示例的设置过程和生成说明。
Windows 进程激活服务 (WAS) 是 Windows Server 2008 新增的进程激活机制,它向使用非 HTTP 协议的应用程序提供了与类似 IIS 的功能,这些功能以前只对基于 HTTP 的应用程序可用。Windows Communication Foundation (WCF) 使用侦听器适配器接口传递激活请求,该激活请求通过由 WCF 支持的非 HTTP 协议(如 TCP、命名管道和 MSMQ)接收。用于通过非 HTTP 协议接收请求的功能由 SMSvcHost.exe 中运行的托管 Windows 服务承载。
Net.Msmq Listener Adapter 服务 (NetMsmqActivator) 根据队列中的消息激活排队的应用程序。
客户端从事务范围内向服务发送采购订单。服务在事务中接收订单并处理订单。然后服务使用订单状态回调客户端。为了便于双向通信,客户端和服务都使用队列以便将采购订单和订单状态排入队列。
服务协定 IOrderProcessor
定义使用队列的单向服务操作。服务操作使用答复终结点将订单状态发送到客户端。答复终结点的地址是用于将订单状态发回客户端的队列的 URI。订单处理应用程序实现下面的协定。
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po,
string reportOrderStatusTo);
}
向其发送订单状态的答复协定由客户端指定。客户端实现订单状态协定。服务使用下面协定的生成的客户端将订单状态发回客户端。
[ServiceContract]
public interface IOrderStatus
{
[OperationContract(IsOneWay = true)]
void OrderStatus(string poNumber, string status);
}
服务操作处理提交的采购订单。对服务操作应用 OperationBehaviorAttribute 以在用于从队列中接收消息的事务中指定自动登记,并指定在服务操作完成时事务自动完成。Orders
类封装了订单处理功能。在本例中,它将采购订单添加到字典。Orders
类中的操作可以使用服务操作登记的事务。
服务操作除了处理提交的采购订单之外,还向客户端答复有关订单状态的信息。
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po, string reportOrderStatusTo)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
Console.WriteLine("Sending back order status information");
NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding();
msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;
OrderStatusClient client = new OrderStatusClient(msmqCallbackBinding, new EndpointAddress(reportOrderStatusTo));
// please note that the same transaction that is used to dequeue purchase order is used
// to send back order status
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
client.OrderStatus(po.PONumber, po.Status);
scope.Complete();
}
}
要使用的客户端绑定是使用配置文件指定的。
MSMQ 队列名称是在配置文件的 appSettings 节中指定的。服务的终结点是在配置文件的 System.serviceModel 节中定义的。
提示
MSMQ 队列名称和终结点地址使用略有不同的寻址约定。MSMQ 队列名称使用圆点 (.)来表示本地计算机,并在其路径中使用反斜杠分隔符。WCF 终结点地址指定一个 net.msmq: 方案,使用“localhost”来表示本地计算机,并在其路径中使用正斜杠。若要从在远程计算机上承载的队列读取数据,请将“.”和“localhost”替换为远程计算机名。
使用一个以类名作为名称的 .svc 文件来承载 WAS 中的服务代码。
Service.svc 文件本身包含用于创建 OrderProcessorService
的指令。
<%@ServiceHost language="c#" Debug="true" Service="Microsoft.ServiceModel.Samples.OrderProcessorService"%>
Service.svc 文件还包含一个程序集指令以确保加载 System.Transactions.dll。
<%@Assembly name="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"%>
客户端创建事务范围。与服务的通信在事务范围内进行,从而可以将事务范围视为所有消息在其中成功或失败的原子单元。通过在事务范围上调用 Complete 可以提交事务。
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderStatusService)))
{
// Open the ServiceHostBase to create listeners and start listening
// for order status messages.
serviceHost.Open();
// Create a proxy with given client endpoint configuration
OrderProcessorClient client = new OrderProcessorClient();
// Create the purchase order
PurchaseOrder po = new PurchaseOrder();
po.CustomerId = "somecustomer.com";
po.PONumber = Guid.NewGuid().ToString();
PurchaseOrderLineItem lineItem1 = new PurchaseOrderLineItem();
lineItem1.ProductId = "Blue Widget";
lineItem1.Quantity = 54;
lineItem1.UnitCost = 29.99F;
PurchaseOrderLineItem lineItem2 = new PurchaseOrderLineItem();
lineItem2.ProductId = "Red Widget";
lineItem2.Quantity = 890;
lineItem2.UnitCost = 45.89F;
po.orderLineItems = new PurchaseOrderLineItem[2];
po.orderLineItems[0] = lineItem1;
po.orderLineItems[1] = lineItem2;
//Create a transaction scope.
using (TransactionScope scope = new
TransactionScope(TransactionScopeOption.Required))
{
// Make a queued call to submit the purchase order
client.SubmitPurchaseOrder(po,
"net.msmq://localhost/private/ServiceModelSamples/OrderStatus");
// Complete the transaction.
scope.Complete();
}
//Closing the client gracefully closes the connection and cleans up
//resources
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
// Close the ServiceHostBase to shutdown the service.
serviceHost.Close();
}
客户端代码实现 IOrderStatus
协定以便从服务接收订单状态。在本例中,它输出订单状态。
[ServiceBehavior]
public class OrderStatusService : IOrderStatus
{
[OperationBehavior(TransactionAutoComplete = true,
TransactionScopeRequired = true)]
public void OrderStatus(string poNumber, string status)
{
Console.WriteLine("Status of order {0}:{1} ",
poNumber , status);
}
}
订单状态队列在 Main
方法中创建。客户端配置包括订单状态服务配置,以便承载订单状态服务,如下面的示例配置所示。
<appSettings>
<!-- use appSetting to configure MSMQ queue name -->
<add key="targetQueueName" value=".\private$\ServiceModelSamples/service.svc" />
<add key="responseQueueName" value=".\private$\ServiceModelSamples/OrderStatus" />
</appSettings>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderStatusService">
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamples/OrderStatus"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderStatus" />
</service>
</services>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamples/service.svc"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</client>
</system.serviceModel>
运行示例时,客户端和服务活动将显示在服务器和客户端控制台窗口中。您可以看到服务器从客户端接收消息。在每个控制台窗口中按 Enter 可以关闭服务器和客户端。
客户端显示由服务器发送的订单状态信息:
Press <ENTER> to terminate client.
Status of order 70cf9d63-3dfa-4e69-81c2-23aa4478ebed :Pending
设置、生成和运行示例
确保已经执行了 Windows Communication Foundation 示例的一次性安装过程。此外,必须安装 WCF 非 HTTP 激活组件:
- 从**“开始”菜单中,选择“控制面板”**。
- 选择**“程序”,然后选择“程序和功能”,或者在经典视图中选择“程序和功能”**。
- 单击**“打开或关闭 Windows 功能”**。
- 在**“功能摘要”下,单击“添加功能”**。
- 展开**“Microsoft .NET Framework 3.0”节点并选中“Windows Communication Foundation 非 HTTP 激活”[Windows Communication Foundation Non-HTTP Activation]**功能。
若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。
通过从命令窗口执行 client.exe 运行客户端。这将创建队列并向其发送消息。让客户端保持运行以观察服务读取消息的结果
在默认情况下 MSMQ 激活服务将作为网络服务运行。因此,用于激活应用程序的队列必须具有对网络服务的接收和查看权限。可以通过使用消息队列 MMC 来添加这些权限:
- 在**“开始”菜单上,单击“运行”**,然后键入 Compmgmt.msc 并按 Enter。
- 在**“服务和应用程序”下,展开“消息队列”**。
- 单击**“专用队列”**。
- 右击队列 (servicemodelsamples/Service.svc) 并选择**“属性”**。
- 在**“安全”选项卡上,单击“添加”**并向网络服务授予查看和接收权限。
将 Windows 进程激活服务 (WAS) 配置为支持 MSMQ 激活。
- 运行 Inetmgr.exe。
- 若要启用默认的网站以便通过 net.msmq 协议进行通信,必须添加新的网站绑定。为此,运行示例目录中的命令文件 AddMsmqSiteBinding.cmd。
如果您以前没有进行此操作,应确保启用 MSMQ 激活服务。在**“开始”菜单上,单击“运行”,然后键入 Services.msc。在服务列表中搜索“Net.Msmq 侦听器适配器”。单键单击并选择“属性”。将“启动类型”设置为“自动”,单击“应用”,然后单击“启动”**按钮。此步骤只能在第一次使用 Net.Msmq Listener Adapter 服务之前操作一次。
若要用单机配置或跨计算机配置来运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。此外,在客户端上更改用于提交采购订单的代码,使其在提交采购订单时在队列的 URI 中反映计算机名。使用以下代码:
client.SubmitPurchaseOrder(po, "net.msmq://localhost/private/ServiceModelSamples/OrderStatus");
默认情况下对 netMsmqBinding 绑定传输启用了安全性。MsmqAuthenticationMode 和 MsmqProtectionLevel 这两个属性共同确定了传输安全性的类型。默认情况下,身份验证模式设置为 Windows,保护级别设置为 Sign。MSMQ 必须是域的成员才可以提供身份验证和签名功能。如果在不是域成员的计算机上运行此示例,则会接收以下错误:“用户的内部消息队列证书不存在”。
在加入到工作组的计算机上运行此示例
如果计算机不是域成员,请将身份验证模式和保护级别设置为 None 以禁用传输安全性,如下面的示例配置所示。
<bindings> <netMsmqBinding> <binding configurationName="TransactedBinding"> <security mode="None"/> </binding> </netMsmqBinding> </bindings>
在运行示例前更改服务和客户端上的配置。
提示
将 security mode 设置为 None 等效于将 MsmqAuthenticationMode、MsmqProtectionLevel 和 Message 安全设置为 None。
若要在加入到工作组的计算机上启用激活,必须使用特定用户帐户运行激活服务和辅助进程(两者使用的账户必须相同),并且队列必须具有该特定用户帐户的 ACL。
更改运行辅助进程所用的标识:
- 运行 Inetmgr.exe。
- 在**“应用程序池”下右键单击“AppPool”(通常为“DefaultAppPool”)并选择“设置应用程序池默认设置…”**。
- 更改标识属性以使用特定用户帐户。
更改运行激活服务所使用的标识:
- 运行 Services.msc。
- 右键单击**“Net.Msmq Listener Adapter”,然后选择“属性”**。
更改**“登录”**选项卡中的账户。
在工作组中,服务还必须使用不受限制的令牌来运行。为此,请在命令窗口中运行下面的命令:
sc sidtype netmsmqactivator unrestricted
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.