次の方法で共有


セッションとキュー

セッション サンプルでは、メッセージ キュー (MSMQ) トランスポート経由でキューに置かれた通信で、関連する一連のメッセージを送受信する方法を示します。 このサンプルでは、 netMsmqBinding バインドを使用します。 このサービスは、キューに登録されたメッセージを受信しているサービスを監視できるようにするためのセルフホステッド コンソール アプリケーションです。

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

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

クライアントは、グループ内の相互に関連するメッセージのセットを送信することがあります。 メッセージを一緒に処理する必要がある場合、または指定した順序でメッセージを処理する必要がある場合は、キューを使用してそれらをグループ化し、単一の受信側アプリケーションで処理することができます。 これは、サーバーのグループに複数の受信アプリケーションがあり、メッセージのグループが同じ受信側アプリケーションによって処理されるようにする必要がある場合に特に重要です。 キューに登録されたセッションは、一度に処理する必要がある関連するメッセージのセットを送受信するために使用されるメカニズムです。 キューに登録されたセッションでは、このパターンを示すトランザクションが必要です。

このサンプルでは、クライアントは、1 つのトランザクションのスコープ内のセッションの一部として、サービスに多数のメッセージを送信します。

サービス コントラクトは 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();
}

サービスは、最初の操作がトランザクションに参加するが、トランザクションを自動的に完了しないようにサービス操作を定義します。 後続の操作も同じトランザクションに参加しますが、自動的には完了しません。 セッションの最後の操作によって、トランザクションが自動的に完了します。 したがって、サービス コントラクト内の複数の操作呼び出しに同じトランザクションが使用されます。 いずれかの操作で例外がスローされた場合、トランザクションはロールバックされ、セッションはキューに戻されます。 最後の操作が正常に完了すると、トランザクションがコミットされます。 サービスは、 PerSessionInstanceContextMode として使用して、サービスの同じインスタンス上のセッション内のすべてのメッセージを受信します。

[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();
}

セッション内のすべてのメッセージに対して 1 つのトランザクションのみを使用でき、トランザクションをコミットする前にセッション内のすべてのメッセージを送信する必要があります。 クライアントを閉じると、セッションが閉じます。 そのため、セッション内のすべてのメッセージをキューに送信するには、トランザクションが完了する前にクライアントを閉じる必要があります。

サンプルを実行すると、クライアントとサービスのアクティビティが、サービスとクライアントの両方のコンソール ウィンドウに表示されます。 サービスがクライアントからメッセージを受信しているのを確認できます。 各コンソール ウィンドウで 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 Samplesの実行」の手順に従います。

既定では、 NetMsmqBindingではトランスポート セキュリティが有効になっています。 MSMQ トランスポート セキュリティには、 MsmqAuthenticationModeMsmqProtectionLevel. の 2 つの関連プロパティがあります。既定では、認証モードは 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に設定することと同じです。