インターネット インフォメーション サービス ホスティングのベスト プラクティス
このトピックでは、Windows Communication Foundation (WCF) サービスのホスティングのベスト プラクティスをいくつか説明します。
WCF サービスの DLL としての実装
Web アプリケーションの \bin ディレクトリに展開される DLL として WCF サービスを実装すると、Web アプリケーション モデルの外部 (IIS を展開できないテスト環境など) でサービスを再利用できるようになります。
IIS でホストされるアプリケーションでのサービス ホスト
IIS ホスト環境によってネイティブにサポートされていないネットワーク トランスポートで待機する新しいサービス ホストを作成する場合は、強制自己ホスト API を使用しないでください (たとえば、TCP サービスをホストする IIS 6.0。これは、TCP 通信が IIS 6.0 ではネイティブにサポートされていないためです)。 この方法は推奨されません。 強制的に作成されたサービス ホストは、IIS ホスト環境内で認識されないからです。 重要な点は、IIS がホスト アプリケーション プールがアイドル状態であるかどうかを判断するときに、強制的に作成されたサービスによって実行される処理が IIS によって考慮されないことです。 この結果、強制的に作成されたサービス ホストを持つアプリケーションは、IIS ホスト プロセスを積極的に廃棄する IIS ホスト環境を持つことになります。
URI と IIS でホストされるエンドポイント
IIS でホストされるサービスのエンドポイントは、絶対アドレスではなく、相対 URI (Uniform Resource Identifier) を使用して構成する必要があります。 これにより、エンドポイント アドレスが、ホスト アプリケーションに属する URI アドレスのセット内に確実に含まれ、メッセージに基づくアクティベーションが正常に行われるようになります。
状態管理とプロセスのリサイクル
IIS ホスト環境は、メモリにローカル状態を保持しないサービスに最適化されています。 IIS は、さまざまな外部および内部イベントに応答してホスト プロセスをリサイクルするため、メモリのみに格納される揮発性の状態はすべて失われます。 IIS でホストされるサービスは、それぞれの状態をプロセスの外部 (データベースなど)、またはアプリケーションのリサイクル イベントが発生した場合に簡単に再作成できるメモリ内キャッシュに格納する必要があります。
Note
メッセージ レイヤーの信頼性とセキュリティを確保するために WCF によって使用されるプロトコルは、揮発性のメモリ内状態を使用します。 WCF の信頼できるセッションおよびセキュリティ セッションは、アプリケーションのリサイクルにより、予期しないときに終了する場合があります。 これらのプロトコルを利用する、IIS でホストされるアプリケーションでは、WCF によって提供されるセッション キー以外の要素 (アプリケーション レイヤー構造やカスタム相関ヘッダーなど) に依存してアプリケーション レイヤーの状態を関連付けるか、ホストされるアプリケーションでの IIS プロセスのリサイクルを無効にする必要があります。
中間層シナリオでのパフォーマンスの最適化
中間層シナリオ (受信メッセージに応答して他のサービスを呼び出すサービス) で最適なパフォーマンスを実現するには、WCF サービス クライアントをリモート サービスに 1 回インスタンス化し、インスタンス化したクライアントを複数の受信要求で繰り返し使用します。 WCF サービス クライアントのインスタンス化は、既存のクライアント インスタンスでのサービスの呼び出しに比べて負荷のかかる処理ですが、中間層シナリオでは、要求全体でリモート クライアントをキャッシュすることでパフォーマンスが大幅に向上します。 WCF サービス クライアントはスレッド セーフであるため、複数のスレッドにわたってクライアントへのアクセスを同期する必要がありません。
また、中間層シナリオでは、svcutil /a
オプションによって生成された非同期 API を使用してパフォーマンスを向上させます。 /a
オプションにより、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) が各サービス操作に対して BeginXXX/EndXXX
メソッドを生成します。これにより、時間のかかる可能性があるリモート サービスへの呼び出しをバックグラウンド スレッドで行うことができます。
マルチホーム シナリオまたはマルチネーム シナリオでの WCF
WCF サービスは、IIS Web ファーム内に配置できます。ここでは、一連のコンピューターが、共通の外部名 (http://www.contoso.com
など) を共有しますが、異なるホスト名によって個別にアドレス指定されます (たとえば、http://www.contoso.com
によって、名前が http://machine1.internal.contoso.com
および http://machine2.internal.contoso.com
の 2 台のコンピューターにトラフィックが転送される場合があります)。 このデプロイ シナリオは、WCF によって完全にサポートされますが、正確な (外部) ホスト名がサービスのメタデータ (Web サービス記述言語) に表示されるように、WCF サービスをホストする IIS Web サイトを特別に構成する必要があります。
WCF によって生成されたサービス メタデータに正確なホスト名が確実に表示されるように、WCF サービスをホストする IIS Web サイトの既定 ID を構成して、明示的なホスト名を使用します。 たとえば、www.contoso.com
ファームの内部に存在するコンピューターでは、HTTP には *:80:www.contoso.com、HTTPS には *:443:www.contoso.com という IIS サイト バインディングを使用する必要があります。
Microsoft 管理コンソール (MMC) スナップインを使用して、IIS Web サイト バインディングを構成できます。
異なるユーザー コンテキストで実行されるアプリケーション プールが、一時フォルダー内の他のアカウントのアセンブリを上書きする
異なるユーザー コンテキストで実行されているアプリケーション プールが、一時的な ASP.NET ファイル フォルダー内の他のアカウントのアセンブリを上書きできないようにするには、アプリケーションごとに個別の ID と一時フォルダーを使用します。 たとえば、/Application1 と /Application2 という 2 つの仮想アプリケーションがある場合は、2 つの異なる ID を使用して、A と B の 2 つのアプリケーション プールを作成できます。 アプリケーション プール A は、一方のユーザー ID (user1) の下で、アプリケーション プール B は、もう一方のユーザー ID (user2) の下で実行でき、/Application1 が A を、/Application2 が B を使用するように構成します。
Web.config で、<system.web/compilation/@tempFolder> を使用して一時フォルダーを構成できます。 /Application1 には "c:\tempForUser1" を、/Application2 には "c:\tempForUser2" を構成できます。 これらのフォルダーに対応する書き込みアクセス許可を 2 つの ID に与えます。
これで、user2 は、(c:\tempForUser1 の下にある) /Application2 のコード生成フォルダーを変更できなくなります。
非同期処理の有効化
既定では、IIS 6.0 以前でホストされている WCF サービス宛てのメッセージは同期的に処理されます。 ASP.NET は、独自のスレッド (ASP.NET のワーカー スレッド) で WCF に呼び出しを行い、WCF は、別のスレッドを使用してその要求を処理します。 WCF は、その処理が完了するまで ASP.NET のワーカー スレッドに保持されます。 このため、要求は同期的に処理されます。 要求を非同期で処理すると、要求の処理に必要なスレッド数が減るため、優れたスケーラビリティが得られます。つまり、WCF が、要求の処理中に ASP.NET のスレッドで保持されません。 サーバーへのサービス拒否 (DOS) 攻撃を可能にする受信要求を抑制する方法がないため、IIS 6.0 を実行しているコンピューターで非同期動作を使用することはお勧めしません。 IIS 7.0 以降では、同時要求スロットルが導入されています[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0]"MaxConcurrentRequestsPerCpu
。 この新しいスロットルにより、非同期処理を安全に使用することができます。 IIS 7.0 の既定では、非同期のハンドラーとモジュールが登録されます。 この機能が無効になっている場合は、アプリケーションの Web.config ファイルで要求の非同期処理を手動で有効にすることができます。 使用する設定は、aspNetCompatibilityEnabled
設定によって異なります。 aspNetCompatibilityEnabled
を false
に設定している場合は、次の構成スニペットに示すように、System.ServiceModel.Activation.ServiceHttpModule
を構成します。
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules>
<remove name="ServiceModel"/>
<add name="ServiceModel"
preCondition="integratedMode,runtimeVersionv2.0"
type="System.ServiceModel.Activation.ServiceHttpModule, System.ServiceModel,Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</modules>
</system.webServer>
aspNetCompatibilityEnabled
を true
に設定している場合は、次の構成スニペットに示すように、System.ServiceModel.Activation.ServiceHttpHandlerFactory
を構成します。
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<handlers>
<clear/>
<add name="TestAsyncHttpHandler"
path="*.svc"
verb="*"
type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</handlers>
</system.webServer>