MsmqActivation 示例演示如何在从消息队列读取的 Windows 进程激活服务(WAS)中托管应用程序。 此示例使用 netMsmqBinding
并基于 Two-Way 通信 示例。 在这种情况下,该服务是 Web 托管的应用程序,客户端是自承载的,并输出到控制台,以观察提交的采购订单的状态。
注释
本示例的设置过程和生成说明位于本主题末尾。
Windows 进程激活服务(WAS)是 Windows Server 2008 的新进程激活机制,它提供类似于 IIS 的功能,这些功能以前仅适用于基于 HTTP 的应用程序,这些功能仅适用于使用非 HTTP 协议的应用程序。 Windows Communication Foundation (WCF) 使用侦听器适配器接口来传达通过 WCF 支持的非 HTTP 协议(如 TCP、命名管道和 MSMQ)接收的激活请求。 通过非 HTTP 协议接收请求的功能由在 SMSvcHost.exe中运行的托管 Windows 服务托管。
Net.Msmq 侦听器适配器服务 (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/ServiceModelSamplesOrder/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
设置、生成和运行示例
确保已安装 IIS 7.0,因为 WAS 激活需要 IIS。
确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。 此外,必须安装 WCF 非 HTTP 激活组件:
在 “开始” 菜单中,选择 “控制面板”。
选择 “程序和功能”。
单击“ 打开或关闭 Windows 功能”。
在 “功能摘要”下,单击“ 添加功能”。
展开 Microsoft .NET Framework 3.0 节点,并检查 Windows Communication Foundation 非 HTTP 激活功能。
若要生成解决方案的 C# 或 Visual Basic .NET 版本,请按照 生成 Windows Communication Foundation 示例中的说明进行操作。
通过从命令窗口执行 client.exe 来运行客户端。 这会创建队列并向队列发送消息。 使客户端保持运行状态,以查看读取消息的服务的结果
默认情况下,MSMQ 激活服务作为网络服务运行。 因此,用于激活应用程序的队列必须具有网络服务的接收和查看权限。 可以通过使用消息队列 MMC 来添加这些权限:
在 “开始 ”菜单中,单击“ 运行”,然后键入
Compmgmt.msc
并按 Enter。在 “服务和应用程序”下,展开 消息队列。
单击 “专用队列”。
右键单击队列(servicemodelsamples/Service.svc),然后选择 “属性”。
在“ 安全 ”选项卡上,单击“ 添加 ”并授予对网络服务的速览和接收权限。
配置 Windows 进程激活服务(WAS)以支持 MSMQ 激活。
为方便起见,以下步骤在示例目录中名为AddMsmqSiteBinding.cmd的批处理文件中实现。
若要支持 net.msmq 激活,必须先将默认网站绑定到 net.msmq 协议。 可以使用随 IIS 7.0 管理工具集一起安装的 appcmd.exe来完成此作。 在提升权限的(管理员)命令提示符下运行以下命令。
%windir%\system32\inetsrv\appcmd.exe set site "Default Web Site" -+bindings.[protocol='net.msmq',bindingInformation='localhost']
注释
此命令是单行文本。
此命令将 net.msmq 网站绑定添加到默认网站。
尽管站点中的所有应用程序共享一个通用的 net.msmq 绑定,但每个应用程序可以单独启用 net.msmq 支持。 若要为 /servicemodelsamples 应用程序启用 net.msmq,请从管理员权限的命令提示符运行以下命令。
%windir%\system32\inetsrv\appcmd.exe set app "Default Web Site/servicemodelsamples" /enabledProtocols:http,net.msmq
注释
此命令是单行文本。
此命令允许通过
http://localhost/servicemodelsamples
和net.msmq://localhost/servicemodelsamples
访问 /servicemodelsamples 应用程序。
如果以前未这样做,请确保已启用 MSMQ 激活服务。 在 “开始 ”菜单中,单击“ 运行”,然后键入
Services.msc
。 搜索 Net.Msmq 侦听器适配器的服务列表。 右键单击并选择“属性”。 将 启动类型 设置为 “自动”,单击“ 应用 ”,然后单击“ 开始 ”按钮。 在 Net.Msmq 侦听器适配器服务首次使用之前,必须执行此步骤一次。要使用单机配置或跨计算机配置运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。 此外,更改提交采购订单的客户端上的代码,以在提交采购订单时反映队列 URI 中的计算机名称。 使用以下代码:
client.SubmitPurchaseOrder(po, "net.msmq://localhost/private/ServiceModelSamples/OrderStatus");
删除为此示例添加的 net.msmq 站点绑定。
为方便起见,以下步骤在示例目录中名为RemoveMsmqSiteBinding.cmd的批处理文件中实现:
通过在具有提升权限的命令提示符处运行以下命令,从启用的协议列表中移除 net.msmq。
%windir%\system32\inetsrv\appcmd.exe set app "Default Web Site/servicemodelsamples" /enabledProtocols:http
注释
此命令是单行文本。
通过在具有提升权限的命令提示符处运行以下命令移除 net.msmq 站点绑定。
%windir%\system32\inetsrv\appcmd.exe set site "Default Web Site" --bindings.[protocol='net.msmq',bindingInformation='localhost']
注释
此命令是单行文本。
警告
运行批处理文件会将 DefaultAppPool 重置为使用 .NET Framework 版本 2.0 运行。
默认情况下, 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.MsmqListener 适配器,然后选择 “属性”。
在 LogOn 选项卡中更改帐户。
在工作组中,服务还必须使用不受限制的令牌来运行。 为此,请在命令窗口中运行以下命令:
sc sidtype netmsmqactivator unrestricted