共用方式為


交易的 MSMQ 系結

Transacted 範例示範如何使用消息佇列 (MSMQ) 來執行交易佇列通訊。

備註

此範例的安裝程式和建置指示位於本主題結尾。

在佇列通訊中,用戶端會使用佇列與服務通訊。 更精確地說,用戶端會將訊息傳送至佇列。 服務會從佇列接收訊息。 因此,服務與用戶端不需要同時執行,即可使用佇列進行通訊。

當交易用來傳送和接收訊息時,實際上有兩個不同的交易。 當用戶端在交易範圍內傳送信息時,交易屬於用戶端及其佇列管理員的本地。 當服務在交易範圍內接收訊息時,交易是專門針對服務與接收佇列管理員的本地交易。 請務必記住,客戶端和服務未參與相同的交易:相反地,在佇列中執行其作業時,它們會使用不同的交易(例如傳送和接收)。

在此範例中,用戶端會從交易範圍內,將一批訊息傳送至服務。 然後,服務會在服務所定義的交易範圍內接收傳送至佇列的訊息。

服務合約為 IOrderProcessor,如下列範例程式代碼所示。 介面會定義適合用於佇列的單向服務。

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true)]
    void SubmitPurchaseOrder(PurchaseOrder po);
}

服務行為會定義作業行為,並將 TransactionScopeRequired 設定為 true。 這可確保方法存取的任何資源管理員都使用用來從佇列擷取訊息的相同交易範圍。 它也保證,如果方法拋出異常,該訊息會傳回佇列。 若未設定此作業行為,佇列通道會建立交易來讀取佇列中的訊息,並在分派之前自動認可該訊息,如此一來,如果作業失敗,訊息就會遺失。 最常見的案例是讓服務作業在用來從佇列讀取訊息的交易中登記,如下列程式代碼所示。

 // This service class that implements the service contract.
 // This added code writes output to the console window.
public class OrderProcessorService : IOrderProcessor
 {
     [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
     public void SubmitPurchaseOrder(PurchaseOrder po)
     {
         Orders.Add(po);
         Console.WriteLine("Processing {0} ", po);
     }
  …
}

服務是自我托管的。 使用 MSMQ 傳輸時,必須事先建立所使用的佇列。 這可以手動或透過程式代碼來完成。 在此範例中,服務包含程式代碼來檢查佇列是否存在,如果佇列不存在,請建立佇列。 佇列名稱會從組態檔讀取。 ServiceModel 元數據公用程式工具 (Svcutil.exe) 會使用基地址來產生服務的 Proxy。

// Host the service within this EXE console application.
public static void Main()
{
    // Get the MSMQ queue name from appSettings 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 OrderProcessorService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
    {
        // 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 shut down the service.
        serviceHost.Close();
    }
}

MSMQ 佇列名稱是在組態檔的 appSettings 區段中指定,如下列範例組態所示。

<appSettings>
    <add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>

備註

當使用 System.Messaging 建立佇列時,佇列名稱會在本機計算機名稱中使用點(.),並在其路徑中以反斜杠作為分隔符。 Windows Communication Foundation(WCF)端點會使用具有 net.msmq 方案的佇列地址,使用 "localhost" 來表示本機電腦,並在路徑中使用正斜線。

用戶端會建立交易範圍。 與佇列的通訊會在交易範圍內進行,因此它被視為一個原子性單位,其中所有訊息要麼都會傳送至佇列,否則沒有任何訊息會被傳送至佇列。 交易會藉由在交易範圍上呼叫 Complete 來認可。

// Create a client.
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);
    // 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();

若要確認交易是否正常運作,請批注交易範圍來修改用戶端,如下列範例程式代碼所示,重建解決方案,然後執行用戶端。

//scope.Complete();

由於交易未完成,因此不會將訊息傳送至佇列。

當您執行範例時,用戶端和服務活動會顯示在服務和用戶端控制台視窗中。 您可以看到服務從用戶端接收訊息。 在每個主控台視窗中按 ENTER 鍵,關閉服務和用戶端。 請注意,由於佇列正在使用中,客戶端和服務不需要同時啟動並執行。 您可以執行用戶端、將其關機,然後啟動服務,但仍會收到訊息。

The service is ready.
Press <ENTER> to terminate service.

Processing Purchase Order: 7b31ce51-ae7c-4def-9b8b-617e4288eafd
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

要設定、建置和執行範例,請執行以下步驟:

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

  2. 如果服務先執行,它會檢查以確定佇列存在。 如果佇列不存在,服務將會建立一個佇列。 您可以先執行服務來建立佇列,也可以透過 MSMQ 佇列管理員建立佇列。 請遵循下列步驟,在 Windows 2008 中建立佇列。

    1. 在 Visual Studio 2012 中開啟伺服器管理員。

    2. 展開 [功能] 索引標籤。

    3. 以滑鼠右鍵按下 私人消息佇列,然後選取 新增私人佇列

    4. 勾選 [交易式] 方塊。

    5. 輸入 ServiceModelSamplesTransacted 作為新佇列的名稱。

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

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

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

若要在加入工作組或未整合 Active Directory 的電腦上執行範例

  1. 如果您的計算機不是網域的一部分,或未安裝 Active Directory 整合,請將驗證模式和保護層級設定為 來 None 關閉傳輸安全性,如下列範例組態程式代碼所示。

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"
                 behaviorConfiguration="OrderProcessorServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint. -->
          <endpoint
              address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
          <!-- 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="OrderProcessorServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. 在執行範例之前,請確定您已在伺服器和用戶端上變更組態。

    備註

    設定 security modeNone 相當於將 MsmqAuthenticationModeMsmqProtectionLevelMessage 的安全性設定為 None