共用方式為


會話和佇列

會話範例示範如何透過消息佇列 (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

設定、建置和執行範例

  1. 請確定您已針對 Windows Communication Foundation 範例 執行One-Time 安裝程式。

  2. 若要建置 C#、C++ 或 Visual Basic .NET 版本的解決方案,請遵循 建置 Windows Communication Foundation 範例中的指示。

  3. 若要在單一或跨計算機組態中執行範例,請遵循執行 Windows Communication Foundation 範例 中的指示。

根據預設, NetMsmqBinding會啟用傳輸安全性。 MSMQ 傳輸安全性有兩個相關屬性,依預設,驗證模式會設定為 MsmqAuthenticationModeMsmqProtectionLevel.Windows而保護層級會設定為 。Sign 若要讓 MSMQ 提供驗證和簽署功能,它必須是網域的一部分,而且必須安裝 MSMQ 的 Active Directory 整合選項。 如果您在不符合這些準則的計算機上執行此範例,您會收到錯誤。

在加入工作組的計算機上執行範例

  1. 如果您的計算機不是網域的一部分,或未安裝 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>
    
  2. 在執行範例之前,請確定您已在伺服器和用戶端上變更組態。

    備註

    將安全性模式設定為None相當於將MsmqAuthenticationModeMsmqProtectionLevelMessage安全性設定為None