WCF トラブルシューティング クイックスタート
このトピックでは、WCF クライアントと WCF サービスの開発時に生じるさまざまな既知の問題の一覧を示します。 発生している問題がこの一覧にない場合は、サービスに対してトレースを構成することをお勧めします。 これにより、トレース ファイル ビューアーで表示し、サービス内で発生することがある例外に関する詳細情報を取得できるトレース ファイルが生成されます。 トレースの構成の詳細については、「 Configuring Tracing」を参照してください。 トレース ファイル ビューアーの詳細については、「 Service Trace Viewer Tool (SvcTraceViewer.exe)」を参照してください。
Windows 7 と IIS のインストール後に WCF サービスを参照しようとすると、"HTTP エラー 404.3 - Not Found" というエラー メッセージが表示されます
HTTP エラー 404.3 - Not Found 拡張構成により、要求しているページは使用できません。 ページがスクリプトの場合は、ハンドラーを追加します。 ファイルをダウンロードする場合は、MIME マップを追加します。 エラーの詳細: InformationModule StaticFileModule。
最初の要求の後でクライアントがしばらくアイドル状態になった場合、2 番目の要求で MessageSecurityException を受け取ることがあります。 状況
サービスとクライアントの動作に問題はないのですが、クライアントが別のコンピューター上にあるときにサービスとクライアントがうまく動作しません。 どうしてでしょうか。
サービスで X.509 証明書を使用していますが、System.Security.Cryptography.CryptographicException を受け取ります。 どうしてでしょうか。
操作の最初のパラメーターを大文字から小文字に変更したら、クライアントが例外をスローするようになりました。 どうしてでしょうか。
トレース ツールの 1 つを使用していますが、EndpointNotFoundException を受け取りました。 どうしてでしょうか。
WCF SOAP アプリケーションから WCF Web HTTP アプリケーションを呼び出すと、サービスから "405 メソッドは許可されていません" というエラーが返されます
ベース アドレスについて教えてください。 エンドポイント アドレスとどのように関連していますか。
Windows 7 と IIS のインストール後に WCF サービスを参照しようとすると、"HTTP エラー 404.3 - Not Found" というエラー メッセージが表示されます
エラー メッセージの全文は次のとおりです。
HTTP エラー 404.3 - Not Found 拡張構成により、要求しているページは使用できません。 ページがスクリプトの場合は、ハンドラーを追加します。 ファイルをダウンロードする場合は、MIME マップを追加します。 エラーの詳細: InformationModule StaticFileModule。
このエラー メッセージは、[Windows Communication Foundation HTTP Activation] がコントロール パネルで明示的に設定されていない場合に表示されます。 これを設定するには、コントロール パネルに移動し、ウィンドウの左下にある [プログラム] をクリックします。 [Windows の機能の有効化または無効化] をクリックします。 [Microsoft .NET Framework 3.5.1] を展開し、[Windows Communication Foundation HTTP Activation] をクリックします。
最初の要求の後でクライアントがしばらくアイドル状態になった場合、2 番目の要求で MessageSecurityException を受け取ることがあります。 状況
2 番目の要求は、主に次の 2 つの理由から失敗する可能性があります。(1) セッションがタイムアウトした。(2) サービスをホストしている Web サーバーがリサイクルされている。 最初の理由の場合、セッションはサービスがタイムアウトするまで有効です。サービスは、サービスのバインディング (ReceiveTimeout) で指定された期間内にクライアントから要求を受信しなかった場合、セキュリティ セッションを終了します。 それ以降のクライアント メッセージでは、 MessageSecurityExceptionが発生します。 クライアントは、セキュリティで保護されたセッションをサービスとの間に再度確立して、後続のメッセージを送信するか、ステートフルなセキュリティ コンテキスト トークンを使用する必要があります。 また、ステートフルなセキュリティ コンテキスト トークンによって、セキュリティで保護されたセッションは、再利用される Web サーバーで存続することができます。 セキュリティで保護されたセッションでステートフルなセキュリティ コンテキスト トークンを使用する方法の詳細については、「方法: セキュリティで保護されたセッションに対しセキュリティ コンテキスト トークンを作成する」を参照してください。 また、セキュリティで保護されたセッションは無効にできます。 <wsHttpBinding> バインディングを使用する場合は、establishSecurityContext
プロパティを false
に設定して、セキュリティで保護されたセッションを無効にできます。 その他のバインディングでセキュリティで保護されたセッションを無効にするには、カスタム バインディングを作成する必要があります。 カスタム バインディングの作成の詳細については、「 How to: Create a Custom Binding Using the SecurityBindingElement」を参照してください。 このオプションを適用する前に、アプリケーションのセキュリティ要件を確認する必要があります。
サービスと対話しているクライアントの数が約 10 個になると、サービスが新しいクライアントを拒否し始めます。 状況
既定では、サービスは、10 個の同時セッションだけをサポートできます。 したがって、サービス バインディングでセッションを使用する場合、サービスは 10 個に到達するまで新しいクライアント接続を受け入れますが、その数に到達した後は、現在実行中のセッションの 1 つが終了するまで新しいクライアント接続を拒否します。 いくつかの方法で、より多くのクライアントをサポートできます。 サービスにセッションが必要ない場合、セッションの多いバインディングを使用しないでください (詳細については、「セッションの使用」を参照してください。)他には、MaxConcurrentSessions プロパティの値をユーザーの環境に適した数値に変更することによって、セッションの制限値を増やす方法があります。
WCF アプリケーションの構成ファイル以外の場所からサービス構成を読み込むことはできますか。
できます。ただし、 ServiceHost メソッドをオーバーライドするカスタムの ApplyConfiguration クラスを作成する必要があります。 そのメソッドでは、ベースを呼び出して最初に構成を読み込むことができますが (標準の構成情報も読み込む場合)、構成読み込みシステム全体を置き換えることもできます。 アプリケーションの構成ファイルとは異なる構成ファイルから構成を読み込む場合は、構成ファイルを自分で解析して構成を読み込む必要があります。
ApplyConfiguration メソッドをオーバーライドし、エンドポイントを直接構成する方法を次のコード例に示します。
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
Console.WriteLine("MyServiceHost Constructor");
}
protected override void ApplyConfiguration()
{
string straddress = GetAddress();
Uri address = new Uri(straddress);
Binding binding = GetBinding();
base.AddServiceEndpoint(typeof(IData), binding, address);
}
string GetAddress()
{
return "http://MyMachine:7777/MyEndpointAddress/";
}
Binding GetBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
return binding;
}
}
サービスとクライアントの動作に問題はないのですが、クライアントが別のコンピューター上にあるときにサービスとクライアントがうまく動作しません。 どうしてでしょうか。
例外によっては、次のようないくつかの問題が存在する可能性があります。
場合によっては、クライアントのエンドポイント アドレスを "localhost" ではなくホスト名に変更する必要があります。
場合によっては、アプリケーションに対してポートを開く必要があります。 詳細については、SDK サンプルから「 Firewall Instructions 」を参照してください。
考えられる他の問題については、サンプルに関するトピック「Windows Communication Foundation サンプルの実行」を参照してください。
クライアントが Windows 資格情報を使用し、例外が SecurityNegotiationExceptionの場合、次のように Kerberos を設定します。
クライアントの App.config ファイルのエンドポイント要素に ID 資格情報を追加します。
<endpoint address="http://MyServer:8000/MyService/" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceExample" contract="IServiceExample" behaviorConfiguration="ClientCredBehavior" name="WSHttpBinding_IServiceExample"> <identity> <userPrincipalName value="name@corp.contoso.com"/> </identity> </endpoint>
System または NetworkService アカウントで自己ホスト型サービスを実行します。 次のコマンドを実行すると、System アカウントでコマンド ウィンドウを作成できます。
at 12:36 /interactive "cmd.exe"
既定でサービス プリンシパル名 (SPN) アカウントを使用するインターネット インフォメーション サービス (IIS) でのサービスをホストします。
SetSPN を使用してドメインに新しい SPN を登録します。 この操作を行えるのは、ドメイン管理者のみです。
Kerberos プロトコルの詳細については、「WCF で使用されるセキュリティの概要」を参照してください。
型が例外である場合に FaultException<Exception> をスローすると、必ずクライアントで、ジェネリック型ではなく一般的な FaultException 型を受け取ります。 どうしてでしょうか。
独自のカスタム エラー データ型を作成し、エラー コントラクトで詳細な型としてその型を宣言することをお勧めします。 その理由は、システム指定の例外型を使用すると、次のような状況が起こるためです。
サービス指向アプリケーションの長所の 1 つを排除する型依存関係が作成されます。
標準的な方法でシリアル化している例外に依存できません。 SecurityExceptionのような例外はまったくシリアル化できない可能性があります。
クライアントに内部実装の詳細が公開されます。 詳細については、「コントラクトおよびサービスのエラーの指定と処理」を参照してください。
ただし、アプリケーションをデバッグしている場合、 ServiceDebugBehavior クラスを使用することによって例外情報をシリアル化して、その情報をクライアントに返すことができます。
応答にデータがない場合、一方向操作と要求/応答操作が戻る速度がほぼ同じになるようです。 どうしてでしょうか。
操作を一方向に指定すると、操作コントラクトは入力メッセージを受け入れるだけで、出力メッセージを返しません。 WCF では、送信データがネットワークに書き込まれるか、例外がスローされたとき、すべてのクライアント呼び出しが戻ります。 一方向操作は同様に動作し、この操作では、サービスが見つからない場合は例外をスローし、サービスがネットワークからのデータの受け入れ準備を完了していない場合はブロックできます。 このため、WCF では通常、一方向呼び出しは要求/応答よりも速くクライアントに戻りますが、ネットワーク上でデータの送信速度が遅くなると、一方向操作の速度も要求/応答操作の速度と同様に遅くなります。 詳細については、「一方向サービス」および「WCF クライアントを使用したサービスへのアクセス」を参照してください。
サービスで X.509 証明書を使用していますが、System.Security.Cryptography.CryptographicException を受け取ります。 どうしてでしょうか。
この例外は通常、IIS ワーカー プロセスの実行に使用しているユーザー アカウントを変更すると発生します。 たとえば、Windows XP で、既定のユーザー アカウントを使用して Aspnet_wp.exe を実行しているときにそのアカウントを ASPNET からカスタムのユーザー アカウントに変更した場合、このエラーが発生します。 秘密キーを使用している場合、そのキーを使用するプロセスには、そのキーを格納しているファイルにアクセスするためのアクセス許可が必要になります。
この場合、秘密キーを格納しているファイルについて、プロセスのアカウントに読み取りアクセス権を与える必要があります。 たとえば、IIS ワーカー プロセスを Bob というアカウントで実行している場合、秘密キーを格納しているファイルへの読み取りアクセス権を Bob に与える必要があります。
特定の X.509 証明書について、秘密キーを格納しているファイルへのアクセス権を適切なユーザー アカウントに与える方法については、「方法: X.509 証明書を WCF からアクセス可能にする」を参照してください。
操作の最初のパラメーターを大文字から小文字に変更したら、クライアントが例外をスローするようになりました。 どうしてでしょうか。
操作シグネチャのパラメーター名の値はコントラクトに含まれ、大文字と小文字が区別されます。 ローカル パラメーター名と、クライアント アプリケーションの操作を記述するメタデータを区別する必要がある場合は、 System.ServiceModel.MessageParameterAttribute 属性を使用します。
トレース ツールの 1 つを使用していますが、EndpointNotFoundException を受け取りました。 どうしてでしょうか。
使用しているトレース ツールが、システム指定の WCF トレース機構でなく、アドレス フィルターの不一致があることを示す EndpointNotFoundException を受け取った場合は、ClientViaBehavior クラスを使用してメッセージをトレース ユーティリティに送信し、そのユーティリティがそのメッセージをサービス アドレスにリダイレクトするようにする必要があります。 ClientViaBehavior クラスは、 Via
アドレス指定ヘッダーを変更して、 To
アドレス指定ヘッダーで示されている最終受信者とは別に、次のネットワーク アドレスを指定します。 ただし、このとき、エンドポイント アドレスは To
値の設定に使用されるので変更しないでください。
次のコード例は、クライアント構成ファイルの例を示しています。
<endpoint
address="http://localhost:8000/MyServer/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMyContract"
behaviorConfiguration="MyClient"
contract="IMyContract"
name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
<endpointBehaviors>
<behavior name="MyClient">
<clientVia viaUri="http://localhost:8001/MyServer/"/>
</behavior>
</endpointBehaviors>
</behaviors>
ベース アドレスについて教えてください。 エンドポイント アドレスとどのように関連していますか。
ベース アドレスとは、 ServiceHost クラスのルート アドレスです。 既定では、 ServiceMetadataBehavior クラスをサービス構成に追加する場合、ホストが発行するすべてのエンドポイントの Web サービス記述言語 (WSDL) は、HTTP ベース アドレスから取得され、それにメタデータ動作に提供される相対アドレスと "?wsdl" が追加されます。 ASP.NET と IIS では、ベース アドレスは仮想ディレクトリに相当します。
NetTcpBinding を使用したサービス エンドポイントと MEX エンドポイント間でのポートの共有
サービスのベース アドレスとして net.tcp://MyServer:8080/MyService を指定して次のエンドポイントを追加します。
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
次の構成スニペットに示すように、NetTcpBinding 設定の 1 つを変更するとします。
<bindings>
<netTcpBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
"ハンドルされない例外: System.ServiceModel.AddressAlreadyInUseException: IP エンドポイント 0.0.0.0:9000 には既にリスナーがあります。" というエラーが表示されます。このエラーは、次の構成スニペットに示すように、ポートが異なる完全修飾 URL を MEX エンドポイントに対して指定することで回避できます。
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
WCF SOAP アプリケーションから WCF Web HTTP アプリケーションを呼び出すと、サービスから "405 メソッドは許可されていません" というエラーが返されます
WCF サービスから WCF Web HTTP アプリケーション (WebHttpBinding および WebHttpBehavior を使用するサービス) を呼び出すと、"Unhandled Exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The remote server returned an unexpected response: (405) Method Not Allowed.
" という例外が発生する場合があります。この例外が発生するのは、WCF が送信 OperationContext を受信 OperationContext で上書きするためです。 この問題を解決するには、WCF Web HTTP サービス操作内で OperationContextScope を作成します。 次に例を示します。
public string Echo(string input)
{
using (new OperationContextScope(this.InnerChannel))
{
return base.Channel.Echo(input);
}
}