次の方法で共有


非同期

非同期のサンプルでは、クライアントからサービス操作に非同期的にアクセスする方法と、サービスがその操作を非同期的に実装する方法について説明します。このサンプルは、電卓サービスを実装する「入門サンプル」に基づいています。同期呼び出しまたは非同期呼び出しのどちらを使用するかはローカルで決定され、ネットワーク上のメッセージ送信には影響しません。サービスがいくつかの同期操作を実装している場合も、クライアントからはそのサービス操作に非同期的にアクセスできます。クライアントでサービスが同期的に呼び出される場合でも、サービスは操作を非同期的に実装できます。

ms751505.note(ja-jp,VS.100).gif注 :
このサンプルのセットアップ手順とビルド手順については、このトピックの最後を参照してください。

このサンプルでは、クライアントはコンソール アプリケーション (.exe) で、サービスは自己ホスト型のコンソール アプリケーション (.exe) です。

サービスは、ICalculator インターフェイスを実装します。クライアントは、このインターフェイスで操作を非同期的に呼び出すことができます。これは、Add などの操作に BeginAdd または EndAdd が用意されたことを意味します。

ms751505.note(ja-jp,VS.100).gif注 :
非同期パターンの詳細については、.NET Framework のドキュメントを参照してください。

クライアントでは、これらの非同期操作をサポートするコードが生成されました。クライアントは次のように、/a (async) コマンド オプションを使用して、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) を実行することによって作成されました。

svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples https://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35

次のコードのように、Add 操作の非同期クライアント版のサービス コントラクトが生成されます。

[System.ServiceModel.ServiceContractAttribute(Namespace=
                   "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [System.ServiceModel.OperationContractAttribute(
       AsyncPattern=true)]
    System.IAsyncResult BeginAdd(double n1, double n2, 
                   System.AsyncCallback callback, object asyncState);
    double EndAdd(System.IAsyncResult result);
    
    ...
}

/tcv:Version35 オプションを /async オプションと共に指定すると、生成されたクライアント型では、サービスを呼び出すためのイベント ベースの非同期パターンが実装されます。詳細については、「イベント ベースの非同期パターンの概要」を参照してください。サービス操作に非同期にアクセスするには、次のサンプル コードに示すように、アプリケーションはイベント ハンドラをクライアントの [Operation]Completed イベントに追加し、[Operation]Async メソッド (たとえば AddAsync) を呼び出します。

// Create a client.
CalculatorClient client = new CalculatorClient();

// BeginAdd.
double value1 = 100.00D;
double value2 = 15.99D;

client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);

このサンプルでは、クライアントは AddSubtract の 2 つの操作を非同期的に開始します。

コールバック関数が実行されると、クライアントは [Operation]CompletedEventArgs 入力パラメータの Result プロパティにアクセスして結果を取得します。

static void AddCallback(object sender, AddCompletedEventArgs e)
{
 Console.WriteLine("Add Result: {0}", e.Result);
}

非同期動作はすべてクライアントにとってローカルであり、メッセージのクライアントによる送信方法やサービスによる処理方法には影響ありません。ユーザー インターフェイス (UI) アプリケーションでこのパターンを使用する一般的な理由は、UI スレッドで画面を更新できるようにしておくためです。このパターンは、サービスがクライアントとして機能し、メッセージ処理スレッドをコール アウトから他のサービスに解放する場合でも適用できます。次のセクションでは、サービス操作を非同期にする方法を示します。

サービスは、ICalculator インターフェイスを実装します。次のコードを参照してください。

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract]
    double Add(double n1, double n2);
    
    [OperationContract]
    double Subtract(double n1, double n2);
    
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginMultiply(double n1, double n2,
        AsyncCallback callback, object state);
    double EndMultiply(IAsyncResult ar);

    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginDivide(double n1, double n2, 
        AsyncCallback callback, object state);
    double EndDivide(IAsyncResult ar); 
}

コントラクトの最初の 2 つの操作は、Windows Communication Foundation (WCF) ランタイムにより同期的に呼び出されます。最後の 2 組の操作は、サービスを非同期的に呼び出すために使用されます。このサンプルでは、AsyncPattern プロパティを true に設定します。このプロパティ設定が、.NET Framework 非同期パターンの実装との組み合わせで、ランタイムに対して操作を非同期的に呼び出すよう指示しています。

通常、サービス実装でこのパターンを使用する理由は、ディスクへのアクセス、データベースへのアクセス、別のサービスの呼び出しなど、時間のかかる入出力操作を行う場合にメッセージ処理スレッドを解放することです。このサンプルでは、IAsyncResult を実装してファイルの入出力操作をラップする方法を示します。MathAsyncResult クラスを実装するための基本クラスは、IAsyncResult の独自の実装を記述する際に再使用できます。

ms751505.note(ja-jp,VS.100).gif注 :
このサンプルでは PerCallMultiple を使用して、セッションの多いバインディングのある順序付け動作を回避します。wsHttpBinding では、セキュリティ コンテキストを確立するために、既定によりセッションが使用されます。このことは、クライアントまたはサービスでのメッセージ処理が非同期であるという性質には影響しませんが、応答のタイミングが重要視され、クライアントでは順次コールバックではなく同時コールバックが取得できるようになります。

このサンプルを実行する場合は、操作の要求や応答はクライアントのコンソール ウィンドウに表示されます。Add 要求と Subtract 要求は、非同期的に呼び出されるのでブロックしません。次に、Multiply 操作と Divide 操作がブロックし、これらの結果は要求の送信時に同時に表示されます。最後に、Add 操作と Subtract 操作の結果がクライアントに返されると、その結果が表示されます。AddSubtract のサービスの実装では、非同期コールバックをクライアントに表示するために sleep が使用されます。

Add(100,15.99)
Subtract(145,76.54)
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Add Result: 115.99
Subtract Result: 68.46

スレッド ID はサービスで使用され、AddSubtract のような同期呼び出しが単一のスレッドで処理されることを示します。MultiplyDivide などの非同期呼び出しには、複数のスレッドが含まれます。サービスからの出力を次に示します。

Received Add Synchronously on ThreadID 11:  Sleeping for 3 seconds
Asynchronous call: BeginMultiply on ThreadID 12
Received Subtract Synchronously on ThreadID 12:  Sleeping for 3 seconds
IO thread for * operation on ThreadID 13
EndMultiply called on ThreadID 14
Asynchronous call: BeginDivide on ThreadID 14
IO thread for / operation on ThreadID 13
EndDivide called on ThreadID 14
Returning Add Result on ThreadID 11
Returning Subtract Result on ThreadID 12

.NET Framework 非同期パターンは、クライアントとサービスのどちらか一方、または両方で使用できます。このサンプルが示すように、クライアント側とサービス側の 2 つは独立しています。

サンプルを設定、ビルド、および実行するには

  1. Windows Communication Foundation サンプルの 1 回限りのセットアップの手順」が実行済みであることを確認します。

  2. ソリューションの C# 版または Visual Basic .NET 版をビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。

  3. 単一コンピューター構成か複数コンピューター構成かに応じて、「Running the Windows Communication Foundation Samples」の手順に従います。

ms751505.Important(ja-jp,VS.100).gif 注 :
サンプルは、既にコンピューターにインストールされている場合があります。続行する前に、次の (既定の) ディレクトリを確認してください。

<InstallDrive>:\WF_WCF_Samples

このディレクトリが存在しない場合は、「.NET Framework 4 向けの Windows Communication Foundation (WCF) および Windows Workflow Foundation (WF) のサンプル」にアクセスして、Windows Communication Foundation (WCF) および WF のサンプルをすべてダウンロードしてください。このサンプルは、次のディレクトリに格納されます。

<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Contract\Service\Asynchronous