次の方法で共有


Transacted MSMQ バインド

Transacted サンプルでは、メッセージ キュー (MSMQ) を使用して、キューに格納されたトランザクション通信を実行する方法を示します。

このサンプルのセットアップ手順とビルド手順は、このトピックの最後にあります。

キュー通信では、クライアントはキューを使用してサービスと通信します。 より正確には、クライアントはメッセージをキューに送信します。 サービスはキューからメッセージを受信します。 そのため、サービスとクライアントは、キューを使用して通信するために同時に実行する必要はありません。

トランザクションを使用してメッセージを送受信する場合、実際には 2 つのトランザクションがあります。 クライアントがトランザクションのスコープ内でメッセージを送信すると、トランザクションはクライアントとクライアント キュー マネージャーに対してローカルになります。 サービスがトランザクションのスコープ内でメッセージを受信すると、トランザクションはサービスと受信側キュー マネージャーに対してローカルになります。 クライアントとサービスが同じトランザクションに参加していない点に注意することが非常に重要です。代わりに、キューで操作 (送受信など) を実行するときに、異なるトランザクションを使用しています。

このサンプルでは、クライアントはトランザクションのスコープ内からサービスにメッセージのバッチを送信します。 キューに送信されたメッセージは、サービスによって定義されたトランザクション スコープ内でサービスによって受信されます。

次のサンプル コードに示すように、サービス コントラクトは IOrderProcessor。 このインターフェイスは、キューでの使用に適した一方向サービスを定義します。

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

サービス動作では、 TransactionScopeRequiredtrue に設定された操作の動作を定義します。 これにより、キューからメッセージを取得するために使用されるのと同じトランザクション スコープが、メソッドによってアクセスされるすべてのリソース マネージャーによって使用されるようになります。 また、メソッドが例外をスローした場合、メッセージがキューに返されることを保証します。 この操作の動作を設定しない場合、キューに登録されたチャネルは、キューからメッセージを読み取るトランザクションを作成し、ディスパッチの前に自動的にコミットして、操作が失敗した場合にメッセージが失われるようします。 最も一般的なシナリオは、次のコードに示すように、キューからメッセージを読み取るために使用されるトランザクションにサービス操作を参加させるシナリオです。

 // 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) によってサービスへのプロキシを生成するために使用されます。

// 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の 2 つの関連プロパティがあります。 既定では、認証モードは 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に設定することと同じです。