會話範例示範如何透過消息佇列 (MSMQ) 傳輸,在佇列通訊中傳送和接收一組相關訊息。 這個範例會使用netMsmqBinding綁定。 此服務是自我裝載的控制台應用程式,可讓您觀察接收佇列訊息的服務。
備註
此範例的安裝程式和建置指示位於本主題結尾。
在佇列通訊中,用戶端會使用佇列與服務通訊。 更精確地說,用戶端會將訊息傳送至佇列。 服務會從佇列接收訊息。 因此,服務與用戶端不需要同時執行,即可使用佇列進行通訊。
有時候,用戶端會傳送一組與群組中彼此相關的訊息。 當訊息必須一起處理或依指定順序處理時,佇列可用來將它們分組在一起,以便由單一接收應用程式進行處理。 當伺服器上有數個接收應用程式,而且必須確保相同接收應用程式處理一組訊息時,這特別重要。 佇列會話是一種機制,可用來傳送和接收必須一次處理的所有相關訊息集。 佇列會話需要交易才能顯示此模式。
在範例中,用戶端會將一些訊息傳送至服務,做為單一交易範圍內會話的一部分。
服務合約為 IOrderTaker,其定義適合用於佇列的單向服務。 以下範例程式代碼中所示的合約使用了 SessionMode,表示訊息是會話的一部分。
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface IOrderTaker
{
[OperationContract(IsOneWay = true)]
void OpenPurchaseOrder(string customerId);
[OperationContract(IsOneWay = true)]
void AddProductLineItem(string productId, int quantity);
[OperationContract(IsOneWay = true)]
void EndPurchaseOrder();
}
服務會以這種方式定義其操作,使第一個操作參與到一筆交易中,但不會自動完成該交易。 後續操作也會加入相同的交易,但不會自動完成。 會話中的最後一個作業會自動完成交易。 因此,相同的交易會用於服務合約中的數個作業調用。 如果有任何作業拋出例外狀況,則交易會回滾,並將會話置入佇列中。 在最後一個作業成功完成後,交易就會被提交。 服務會使用 PerSession 做為 InstanceContextMode ,在相同服務實例上的會話中接收所有訊息。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class OrderTakerService : IOrderTaker
{
PurchaseOrder po;
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = false)]
public void OpenPurchaseOrder(string customerId)
{
Console.WriteLine("Creating purchase order");
po = new PurchaseOrder(customerId);
}
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = false)]
public void AddProductLineItem(string productId, int quantity)
{
po.AddProductLineItem(productId, quantity);
Console.WriteLine("Product " + productId + " quantity " +
quantity + " added to purchase order");
}
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = true)]
public void EndPurchaseOrder()
{
Console.WriteLine("Purchase Order Completed");
Console.WriteLine();
Console.WriteLine(po.ToString());
}
}
服務是自我托管的。 使用 MSMQ 傳輸時,必須事先建立所使用的佇列。 這可以手動或透過程式代碼來完成。 在此範例中,服務會包含 System.Messaging 代碼,檢查佇列是否存在,並在需要時建立它。 佇列名稱會使用 AppSettings 類別從組態檔讀取。
// Host the service within this EXE console application.
public static void Main()
{
// Get MSMQ queue name from app settings in configuration.
string queueName = ConfigurationManager.AppSettings["queueName"];
// Create the transacted MSMQ queue if necessary.
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
// Create a ServiceHost for the OrderTakerService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderTakerService)))
{
// Open the ServiceHost to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
// Close the ServiceHost to shutdown the service.
serviceHost.Close();
}
}
MSMQ 佇列名稱是在組態檔的 appSettings 區段中指定。 服務的端點定義於組態檔的 system.serviceModel 區段中,並指定系 netMsmqBinding 結。
<appSettings>
<!-- Use appSetting to configure MSMQ queue name. -->
<add key="queueName" value=".\private$\ServiceModelSamplesSession" />
</appSettings>
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.OrderTakerService"
behaviorConfiguration="CalculatorServiceBehavior">
...
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesSession"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderTaker" />
...
</service>
</services>
...
</system.serviceModel>
用戶端會建立交易範圍。 會話中的所有訊息都會在交易範圍內傳送到佇列,導致其被視為一個所有訊息都要同時成功或失敗的原子性單位。 交易通過呼叫Complete來提交。
//Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
// Create a client with given client endpoint configuration.
OrderTakerClient client = new OrderTakerClient("OrderTakerEndpoint");
// Open a purchase order.
client.OpenPurchaseOrder("somecustomer.com");
Console.WriteLine("Purchase Order created");
// Add product line items.
Console.WriteLine("Adding 10 quantities of blue widget");
client.AddProductLineItem("Blue Widget", 10);
Console.WriteLine("Adding 23 quantities of red widget");
client.AddProductLineItem("Red Widget", 23);
// Close the purchase order.
Console.WriteLine("Closing the purchase order");
client.EndPurchaseOrder();
//Closing the client gracefully closes the connection and cleans up resources.
client.Close();
// Complete the transaction.
scope.Complete();
}
備註
在提交交易之前,您只能針對會話中的所有訊息使用單一交易,並且在提交交易之前會話中的所有訊息必須傳送。 關閉客戶端會關閉工作階段。 因此,必須在交易完成之前關閉客戶端,才能將會話中的所有訊息傳送至佇列。
當您執行範例時,用戶端和服務活動會顯示在服務和用戶端控制台視窗中。 您可以看到服務從用戶端接收訊息。 在每個主控台視窗中按 ENTER 鍵,關閉服務和用戶端。 由於佇列正在使用中,客戶端和服務不需要同時啟動並執行。 您可以執行用戶端、將其關機,然後啟動服務,並仍然接收其訊息。
在用戶端上。
Purchase Order created
Adding 10 quantities of blue widget
Adding 23 quantities of red widget
Closing the purchase order
Press <ENTER> to terminate client.
在服務方面
The service is ready.
Press <ENTER> to terminate service.
Creating purchase order
Product Blue Widget quantity 10 added to purchase order
Product Red Widget quantity 23 added to purchase order
Purchase Order Completed
Purchase Order: 7c86fef0-2306-4c51-80e6-bcabcc1a6e5e
Customer: somecustomer.com
OrderDetails
Order LineItem: 10 of Blue Widget @unit price: $2985
Order LineItem: 23 of Red Widget @unit price: $156
Total cost of this order: $33438
Order status: Pending
設定、建置和執行範例
請確定您已針對 Windows Communication Foundation 範例 執行One-Time 安裝程式。
若要建置 C#、C++ 或 Visual Basic .NET 版本的解決方案,請遵循 建置 Windows Communication Foundation 範例中的指示。
若要在單一或跨計算機組態中執行範例,請遵循執行 Windows Communication Foundation 範例 中的指示。
根據預設, NetMsmqBinding會啟用傳輸安全性。 MSMQ 傳輸安全性有兩個相關屬性,依預設,驗證模式會設定為 MsmqAuthenticationMode ,MsmqProtectionLevel.Windows而保護層級會設定為 。Sign 若要讓 MSMQ 提供驗證和簽署功能,它必須是網域的一部分,而且必須安裝 MSMQ 的 Active Directory 整合選項。 如果您在不符合這些準則的計算機上執行此範例,您會收到錯誤。
在加入工作組的計算機上執行範例
如果您的計算機不是網域的一部分,或未安裝 Active Directory 整合,請將驗證模式和保護層級設定為
None來關閉傳輸安全性,如下列範例組態所示。<system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.OrderTakerService" behaviorConfiguration="OrderTakerServiceBehavior"> <host> <baseAddresses> <add baseAddress= "http://localhost:8000/ServiceModelSamples/service"/> </baseAddresses> </host> <!-- Define NetMsmqEndpoint --> <endpoint address= "net.msmq://localhost/private/ServiceModelSamplesSession" binding="netMsmqBinding" bindingConfiguration="Binding1" contract="Microsoft.ServiceModel.Samples.IOrderTaker" /> <!-- The mex endpoint is exposed at--> <!--http://localhost:8000/ServiceModelSamples/service/mex. --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <bindings> <netMsmqBinding> <binding name="Binding1"> <security mode="None" /> </binding> </netMsmqBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="OrderTakerServiceBehavior"> <serviceMetadata httpGetEnabled="True"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>在執行範例之前,請確定您已在伺服器和用戶端上變更組態。
備註
將安全性模式設定為
None相當於將MsmqAuthenticationMode、MsmqProtectionLevel和Message安全性設定為None。