クライアントを使用したサービスへのアクセス
クライアント アプリケーションがサービスと通信するには、クライアント アプリケーションで WCF クライアント オブジェクトまたは WCF チャネル オブジェクトを作成し、構成してから使用する必要があります。 「WCF クライアントの概要」では、オブジェクトの概要および基本的なクライアントやチャネル オブジェクトの作成と使用に関する手順を説明しています。
このトピックでは、ユーザーのシナリオに応じて役立つ、クライアント アプリケーション、クライアント オブジェクト、およびチャネル オブジェクトに関するいくつかの問題について詳しく説明します。
概要
ここでは、以下の項目に関連する動作と問題について説明します。
チャネルとセッションの有効期間
例外処理
ブロックの問題について
対話方式によるチャネルの初期化
チャネルとセッションの有効期間
Windows Communication Foundation (WCF) アプリケーションには、データグラムとセッションフルという 2 つのカテゴリがあります。
データグラム チャネルは、そこに含まれるすべてのメッセージ間に相関関係がないチャネルです。 データグラム チャネルでは、入出力操作が失敗しても、通常、次の操作は影響を受けないので、同じチャネルの再利用が可能です。 したがって、通常、データグラム チャネルは失敗になりません。
一方、セッションフル チャネルは、他のエンドポイントと関連付けられているチャネルです。 一方のセッション内のメッセージは、他方の同じセッションと常に関連付けられています。 さらに、セッションが成功したとみなされるためには、セッションの両参加要素が、メッセージ交換要件が満たされたということに同意する必要があります。 両参加要素が同意できない場合、セッション チャネルは失敗になる場合があります。
クライアントを明示的に開く場合も暗黙的に開く場合も、最初の操作を呼び出します。
Note
一般的に、障害が生じたセッションフル チャネルを明示的に検出することは有用ではありません。通知されるタイミングがセッションの実装により異なるためです。 たとえば、System.ServiceModel.NetTcpBinding (信頼できるセッションは無効) では TCP 接続のセッションが表面に出るため、サービスまたはクライアントで ICommunicationObject.Faulted イベントをリッスンしていれば、ネットワーク エラーが発生すると直ちに通知される可能性があります。 一方、信頼できるセッション (System.ServiceModel.Channels.ReliableSessionBindingElement を有効化したバインディングにより確立される) は、サービスが小さなネットワーク エラーから分離されるように設計されています。 妥当な期間内にセッションの再確立が可能な場合、信頼できるセッション用に構成された、この同じバインディングは、中断が長期間発生し続けるまでエラーにならない場合があります。
アプリケーション層にチャネルを公開するほとんどのシステム提供のバインディングでは、既定でセッションが使用されますが、System.ServiceModel.BasicHttpBinding では使用されません。 詳細については、「セッションの使用」を参照してください。
セッションの適切な使用
セッションを使用すると、メッセージ交換全体が完了したかどうか、そしてメッセージ交換が成功したと両側が見なしたかどうかを認識できます。 呼び出し側のアプリケーションでは、チャネルを開き、使用して、閉じるまでを 1 つの try ブロック内で処理することをお勧めします。 セッション チャネルが開いているときに、ICommunicationObject.Close メソッドを 1 回呼び出して、その呼び出しが正常に返された場合、セッションは成功しています。 この場合の成功とは、バインディングにより指定されているすべての配信保証が満たされ、もう一方の側では ICommunicationObject.Abort を呼び出す前にチャネルに対して Close を呼び出さなかったことを意味します。
次のセクションで、このクライアントによる方法の例を示します。
例外処理
クライアント アプリケーションで例外を処理することは簡単です。 try ブロック内部でチャネルを開き、使用して、閉じた場合、例外がスローされない限り、メッセージ交換は正常に行われています。 通常、例外がスローされた場合は、メッセージ交換が中止されます。
Note
using
ステートメントUsing
の使用 (Visual Basic での) は推奨されません。 その理由は、using
ステートメントの最後で例外が発生し、認識する必要のある他の例外がマスクされる可能性があるためです。 詳細については、Close と Abort を使用した WCF クライアントのリソースの解放に関するページを参照してください。
次のコード例は、using
文ではなく try/catch ブロックを使用する、推奨されるクライアント パターンを示しています。
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;
public class Client
{
public static void Main()
{
// Picks up configuration from the config file.
SampleServiceClient wcfClient = new SampleServiceClient();
try
{
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));
Console.WriteLine("Press ENTER to exit:");
Console.ReadLine();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (FaultException<GreetingFault> greetingFault)
{
Console.WriteLine(greetingFault.Detail.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (FaultException unknownFault)
{
Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
Console.ReadLine();
wcfClient.Abort();
}
}
}
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation
Public Class Client
Public Shared Sub Main()
' Picks up configuration from the config file.
Dim wcfClient As New SampleServiceClient()
Try
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))
Console.WriteLine("Press ENTER to exit:")
Console.ReadLine()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch greetingFault As FaultException(Of GreetingFault)
Console.WriteLine(greetingFault.Detail.Message)
Console.ReadLine()
wcfClient.Abort()
Catch unknownFault As FaultException
Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
Console.ReadLine()
wcfClient.Abort()
End Try
End Sub
End Class
Note
ICommunicationObject.State プロパティの値を確認すると競合状態になるので、チャネルを再利用するかどうか、またはチャネルを閉じるかどうかを決定するのにこの値を確認することは推奨されません。
データグラム チャネルを閉じるときに例外が発生しても、データグラム チャネルはエラーになりません。 さらに、非双方向クライアントがセキュリティで保護されたメッセージ交換を使用して認証に失敗した場合、通常、System.ServiceModel.Security.MessageSecurityException がスローされます。 しかし、双方向クライアントがセキュリティで保護されたメッセージ交換を使用して認証に失敗した場合、クライアントは代わりに System.TimeoutException を受信します。
アプリケーション レベルでのエラー情報の使用に関する詳細については、「コントラクトおよびサービスのエラーの指定と処理」を参照してください。 予期される例外とその処理方法については、「予期される例外」を参照してください。 チャネルの開発時に発生するエラーの処理方法の詳細については、「例外とエラーの処理」を参照してください。
クライアントのブロックとパフォーマンス
アプリケーションが要求/応答操作を同期的に呼び出す場合、戻り値が受信されるか例外 (System.TimeoutException など) がスローされるまで、クライアントはブロックされます。 この動作はローカルの動作と似ています。 アプリケーションが、WCF クライアント オブジェクトまたはチャネルに対する操作を同期的に呼び出す場合は、チャネル レイヤーがデータをネットワークに書き込むことができるまで、または例外がスローされるまで、クライアントに制御が戻りません。 また、一方向メッセージ交換パターン (OperationContractAttribute.IsOneWay が true
に設定された操作をマークすることで指定される) では、クライアントの応答性が向上する可能性がありますが、バインディングや送信済みのメッセージによっては、一方向操作でもブロックが生じる場合があります。 一方向操作とはメッセージ交換のみを指しています。 詳細については、「一方向サービス」を参照してください。
メッセージ交換パターンに関係なく、大規模データのチャンクによりクライアント処理が遅延する場合があります。 これらの問題の対処方法については、「大規模データとストリーミング」を参照してください。
操作が完了したが、アプリケーションでさらに処理を行う必要がある場合は、WCF クライアントが実装するサービス コントラクト インターフェイスに非同期のメソッドのペアを作成する必要があります。 これを行う最も簡単な方法は、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) で /async
スイッチを使用することです。 例については、「方法: サービス操作を非同期に呼び出す」を参照してください。
クライアント パフォーマンスの向上の詳細については、「中間層クライアント アプリケーション」を参照してください。
ユーザーによる資格情報の動的選択の有効化
IInteractiveChannelInitializer インターフェイスを使用すると、アプリケーションによりユーザー インターフェイスが表示され、ユーザーが資格情報を選択できるようになります。この資格情報は、タイムアウト タイマーが開始される前に、チャネルの作成に使用されます。
アプリケーション開発者は、挿入された IInteractiveChannelInitializer を 2 つの方法で利用できます。 チャネルを開く前 (明示的アプローチ)、または最初の操作を呼び出す前 (暗黙的アプローチ) に、クライアント アプリケーションで ClientBase<TChannel>.DisplayInitializationUI または IClientChannel.DisplayInitializationUI (または非同期バージョン) を呼び出すことができます。
暗黙的方法を使用する場合、アプリケーションは最初の操作を ClientBase<TChannel> または IClientChannel 拡張に対して呼び出す必要があります。 アプリケーションが最初の操作以外の何かを呼び出した場合、例外がスローされます。
明示的方法を使用する場合、アプリケーションで次の手順を順番に実行する必要があります。
ClientBase<TChannel>.DisplayInitializationUI または IClientChannel.DisplayInitializationUI (または非同期バージョン) を呼び出します。
初期化子が返された場合は、Open オブジェクトまたは IClientChannel プロパティで返された IClientChannel オブジェクトの ClientBase<TChannel>.InnerChannel メソッドを呼び出します。
操作を呼び出します。
製品品質のアプリケーションでは、明示的な方法を採用することによってユーザー インターフェイスのプロセスを制御することをお勧めします。
暗黙的な方法を使用するアプリケーションでは、ユーザー インターフェイス初期化子が呼び出されますが、このアプリケーションのユーザーがバインディングの送信タイムアウト期間内に応答できない場合、ユーザー インターフェイスが復帰すると例外がスローされます。