カスタム サービス ホスト

CustomServiceHost サンプルでは、ServiceHost クラスのカスタム 派生クラスを使用して、サービスのランタイム動作を変更する方法を示します。 この方法では、多数のサービスを一般的な方法で構成する代わりに再利用可能な方法が提供されます。 また、このサンプルでは、 ServiceHostFactory クラスを使用して、インターネット インフォメーション サービス (IIS) または Windows プロセス アクティブ化サービス (WAS) ホスティング環境でカスタム ServiceHost を使用する方法も示します。

シナリオについて

機密性の高い可能性があるサービス メタデータが意図せずに漏えいするのを防ぐために、Windows Communication Foundation (WCF) サービスの既定の構成ではメタデータの公開が無効になります。 この動作は既定ではセキュリティで保護されていますが、構成でサービスのメタデータ発行動作が明示的に有効になっていない限り、メタデータ インポート ツール (Svcutil.exeなど) を使用してサービスを呼び出すために必要なクライアント コードを生成できないことも意味します。

多数のサービスに対してメタデータの公開を有効にするには、個々のサービスに同じ構成要素を追加する必要があります。これにより、実質的に同じ構成情報が大量に生成されます。 各サービスを個別に構成する代わりに、メタデータの公開を 1 回有効にする命令型コードを記述し、そのコードを複数の異なるサービスで再利用することもできます。 これを行うには、 ServiceHost から派生し、 ApplyConfiguration() メソッドをオーバーライドしてメタデータ発行動作を強制的に追加する新しいクラスを作成します。

Von Bedeutung

わかりやすくするために、このサンプルでは、セキュリティで保護されていないメタデータ発行エンドポイントを作成する方法を示します。 このようなエンドポイントは、匿名の認証されていないコンシューマーが使用できる可能性があり、そのようなエンドポイントをデプロイする前に注意して、サービスのメタデータを公開することが適切であることを確認する必要があります。

カスタム ServiceHost の実装

ServiceHost クラスは、継承子がオーバーライドしてサービスのランタイム動作を変更できる便利な仮想メソッドをいくつか公開します。 たとえば、 ApplyConfiguration() メソッドは、構成ストアからサービス構成情報を読み取り、それに応じてホストの ServiceDescription を変更します。 既定の実装では、アプリケーションの構成ファイルから構成が読み取られます。 カスタム実装では、 ApplyConfiguration() をオーバーライドして命令型コードを使用して ServiceDescription をさらに変更したり、既定の構成ストアを完全に置き換えたりすることもできます。 たとえば、アプリケーションの構成ファイルではなく、データベースからサービスのエンドポイント構成を読み取ります。

このサンプルでは、この動作がサービスの構成ファイルに明示的に追加されていない場合でも、ServiceMetadataBehavior (メタデータの発行を有効にする) を追加するカスタム ServiceHost を構築します。 これを実現するには、 ServiceHost から継承し、 ApplyConfiguration() をオーバーライドする新しいクラスを作成します。

class SelfDescribingServiceHost : ServiceHost
{
    public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses) { }

    //Overriding ApplyConfiguration() allows us to
    //alter the ServiceDescription prior to opening
    //the service host.
    protected override void ApplyConfiguration()
    {
        //First, we call base.ApplyConfiguration()
        //to read any configuration that was provided for
        //the service we're hosting. After this call,
        //this.Description describes the service
        //as it was configured.
        base.ApplyConfiguration();

        //(rest of implementation elided for clarity)
    }
}

アプリケーションの構成ファイルで提供されている構成は無視したくないので、 ApplyConfiguration() のオーバーライドでは最初に基本実装を呼び出します。 このメソッドが完了したら、次の命令型コードを使用して、 ServiceMetadataBehavior を説明に強制的に追加できます。

ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
    mexBehavior = new ServiceMetadataBehavior();
    this.Description.Behaviors.Add(mexBehavior);
}
else
{
    //Metadata behavior has already been configured,
    //so we do not have any work to do.
    return;
}

ApplyConfiguration() オーバーライドで最後に行う必要があるのは、既定のメタデータ エンドポイントを追加することです。 慣例により、サービス ホストの BaseAddresses コレクション内の URI ごとに 1 つのメタデータ エンドポイントが作成されます。

//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
    if (baseAddress.Scheme == Uri.UriSchemeHttp)
    {
        mexBehavior.HttpGetEnabled = true;
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexHttpBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeHttps)
    {
        mexBehavior.HttpsGetEnabled = true;
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexHttpsBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
    {
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexNamedPipeBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
    {
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexTcpBinding(),
                                "mex");
    }
}

セルフホストでのカスタム ServiceHost の使用

カスタム ServiceHost の実装が完了したので、それを使用して、 SelfDescribingServiceHostのインスタンス内でそのサービスをホストすることで、メタデータ発行動作を任意のサービスに追加できます。 次のコードは、セルフホスト シナリオでの使用方法を示しています。

SelfDescribingServiceHost host =
         new SelfDescribingServiceHost( typeof( Calculator ) );
host.Open();

カスタム ホストは、既定の ServiceHost クラスを使用してサービスをホストしたかのように、アプリケーションの構成ファイルからサービスのエンドポイント構成を読み取ります。 ただし、カスタム ホスト内でメタデータの発行を有効にするロジックを追加したため、構成でメタデータ公開動作を明示的に有効にする必要はなくなりました。 この方法は、複数のサービスを含むアプリケーションを構築していて、同じ構成要素を何度も書き込まずに各サービスに対してメタデータの公開を有効にする場合に、異なる利点があります。

IIS または WAS でのカスタム ServiceHost の使用

カスタム サービス ホストをセルフホスト シナリオで使用するのは簡単です。これは、最終的にサービス ホスト インスタンスの作成と開きを担当するアプリケーション コードであるためです。 ただし、IIS または WAS ホスティング環境では、WCF インフラストラクチャは受信メッセージに応答してサービスのホストを動的にインスタンス化します。 カスタム サービス ホストは、このホスティング環境でも使用できますが、ServiceHostFactory の形式で追加のコードが必要です。 次のコードは、カスタム ServiceHostFactoryのインスタンスを返すSelfDescribingServiceHostの派生を示しています。

public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType,
     Uri[] baseAddresses)
    {
        //All the custom factory does is return a new instance
        //of our custom host class. The bulk of the custom logic should
        //live in the custom host (as opposed to the factory)
        //for maximum
        //reuse value outside of the IIS/WAS hosting environment.
        return new SelfDescribingServiceHost(serviceType,
                                             baseAddresses);
    }
}

ご覧のように、カスタム ServiceHostFactory の実装は簡単です。 すべてのカスタム ロジックは、ServiceHost 実装内に存在します。ファクトリは派生クラスのインスタンスを返します。

サービス実装でカスタム ファクトリを使用するには、サービスの .svc ファイルにメタデータを追加する必要があります。

<% @ServiceHost Service="Microsoft.ServiceModel.Samples.CalculatorService"
               Factory="Microsoft.ServiceModel.Samples.SelfDescribingServiceHostFactory"
               language=c# Debug="true" %>

ここでは、Factory ディレクティブに追加の@ServiceHost属性を追加し、カスタム ファクトリの CLR 型名を属性の値として渡しました。 IIS または WAS がこのサービスのメッセージを受信すると、WCF ホスティング インフラストラクチャは最初に ServiceHostFactory のインスタンスを作成し、次に ServiceHostFactory.CreateServiceHost()を呼び出してサービス ホスト自体をインスタンス化します。

サンプルの実行

このサンプルでは完全に機能するクライアントとサービスの実装を提供しますが、サンプルのポイントは、カスタム ホストを使用してサービスのランタイム動作を変更する方法を説明することです。次の手順を実行します。

カスタム ホストの効果を確認する

  1. サービスの Web.config ファイルを開き、サービスのメタデータを明示的に有効にする構成がないことを確認します。

  2. サービスの .svc ファイルを開き、その @ServiceHost ディレクティブに、カスタム ServiceHostFactory の名前を指定する Factory 属性が含まれていることを確認します。

サンプルを設定、ビルド、実行する

  1. Windows Communication Foundation サンプル One-Time セットアップ手順を実行していることを確認します。

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

  3. ソリューションがビルドされたら、Setup.bat を実行して、IIS 7.0 で ServiceModelSamples アプリケーションを設定します。 ServiceModelSamples ディレクトリが IIS 7.0 アプリケーションとして表示されます。

  4. 単一または複数のコンピューター間の構成でサンプルを実行するには、「Windows Communication Foundation Samplesの実行」の手順に従います。

  5. IIS 7.0 アプリケーションを削除するには、 Cleanup.bat実行します

こちらも参照ください