Partager via


Hôte de service personnalisé

L’exemple CustomServiceHost montre comment utiliser un dérivé personnalisé de la ServiceHost classe pour modifier le comportement d’exécution d’un service. Cette approche offre une alternative réutilisable à la configuration d’un grand nombre de services de manière courante. L’exemple montre également comment utiliser la ServiceHostFactory classe pour utiliser un ServiceHost personnalisé dans l’environnement d’hébergement des services Internet (IIS) ou du service d’activation de processus Windows (WAS).

À propos du scénario

Pour empêcher la divulgation involontaire de métadonnées de service potentiellement sensibles, la configuration par défaut pour les services Windows Communication Foundation (WCF) désactive la publication de métadonnées. Ce comportement est sécurisé par défaut, mais signifie également que vous ne pouvez pas utiliser un outil d’importation de métadonnées (tel que Svcutil.exe) pour générer le code client requis pour appeler le service, sauf si le comportement de publication des métadonnées du service est explicitement activé dans la configuration.

L’activation de la publication de métadonnées pour un grand nombre de services implique l’ajout des mêmes éléments de configuration à chaque service individuel, ce qui entraîne une grande quantité d’informations de configuration essentiellement identiques. En guise d’alternative à la configuration individuelle de chaque service, il est possible d’écrire le code impératif qui permet la publication de métadonnées une seule fois, puis de réutiliser ce code sur plusieurs services différents. Pour ce faire, il faut créer une classe nouvelle qui dérive de ServiceHost et remplace la méthode ApplyConfiguration() pour ajouter impérativement le comportement de publication de métadonnées.

Importante

Pour plus de clarté, cet exemple montre comment créer un point de terminaison de publication de métadonnées non sécurisé. Ces points de terminaison sont potentiellement disponibles pour les consommateurs non authentifiés anonymes et les précautions doivent être prises avant de déployer ces points de terminaison pour s’assurer que la divulgation publique des métadonnées d’un service est appropriée.

Implémentation d’un ServiceHost personnalisé

La ServiceHost classe expose plusieurs méthodes virtuelles utiles que les hériteurs peuvent remplacer pour modifier le comportement d’exécution d’un service. Par exemple, la méthode ApplyConfiguration() lit des informations de configuration du service du magasin de configurations et modifie en conséquence ServiceDescription de l'hôte. L’implémentation par défaut lit la configuration à partir du fichier de configuration de l’application. Les implémentations personnalisées peuvent redéfinir ApplyConfiguration() pour modifier davantage le ServiceDescription en utilisant du code impératif ou même remplacer entièrement le stockage de configuration par défaut. Par exemple, pour lire la configuration du point de terminaison d’un service à partir d’une base de données au lieu du fichier de configuration de l’application.

Dans cet exemple, nous voulons créer un ServiceHost personnalisé qui ajoute Le ServiceMetadataBehavior (qui active la publication de métadonnées), même si ce comportement n’est pas explicitement ajouté dans le fichier de configuration du service. Pour ce faire, créez une classe héritée de ServiceHost et qui remplace 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)
    }
}

Étant donné que nous ne voulons pas ignorer une configuration qui a été fournie dans le fichier de configuration de l'application, la première chose que fait notre surcharge de ApplyConfiguration() est d'appeler l'implémentation de base. Une fois cette méthode terminée, nous pouvons ajouter impérativement le ServiceMetadataBehavior à la description en utilisant le code impératif suivant.

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;
}

La dernière chose que notre substitution ApplyConfiguration() doit faire est ajouter le point de terminaison de métadonnées par défaut. Par convention, un point de terminaison de métadonnées est créé pour chaque URI de la collection BaseAddresses de l’hôte de service.

//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");
    }
}

Utilisation d’un ServiceHost personnalisé dans l’auto-hôte

Maintenant que nous avons terminé notre implémentation ServiceHost personnalisée, nous pouvons l’utiliser pour ajouter un comportement de publication de métadonnées à n’importe quel service en hébergeant ce service à l’intérieur d’une instance de notre SelfDescribingServiceHost. Le code suivant montre comment l’utiliser dans le scénario auto-hôte.

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

Notre hôte personnalisé lit toujours la configuration du point de terminaison du service à partir du fichier de configuration de l’application, comme si nous avions utilisé la classe par défaut ServiceHost pour héberger le service. Toutefois, étant donné que nous avons ajouté la logique pour activer la publication de métadonnées à l’intérieur de notre hôte personnalisé, nous ne devons plus activer explicitement le comportement de publication des métadonnées dans la configuration. Cette approche présente un avantage distinct lorsque vous créez une application qui contient plusieurs services et que vous souhaitez activer la publication de métadonnées sur chacune d’elles sans écrire les mêmes éléments de configuration.

Utilisation d’un ServiceHost personnalisé dans IIS ou WAS

L’utilisation d’un hôte de service personnalisé dans des scénarios auto-hôtes est simple, car il s’agit de votre code d’application qui est finalement responsable de la création et de l’ouverture de l’instance hôte du service. Dans l’environnement d’hébergement IIS ou WAS, toutefois, l’infrastructure WCF instancie dynamiquement l’hôte de votre service en réponse aux messages entrants. Les hôtes de service personnalisés peuvent également être utilisés dans cet environnement d’hébergement, mais ils nécessitent du code supplémentaire sous la forme d’un ServiceHostFactory. Le code suivant montre un dérivé de ServiceHostFactory qui renvoie des instances de notre élément personnalisé 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);
    }
}

Comme vous pouvez le voir, l’implémentation d’un ServiceHostFactory personnalisé est simple. Toute la logique personnalisée réside dans l’implémentation de ServiceHost ; l'usine retourne une instance de la classe dérivée.

Pour utiliser une fabrique personnalisée avec une implémentation de service, nous devons ajouter des métadonnées supplémentaires au fichier .svc du service.

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

Ici, nous avons ajouté un attribut supplémentaire Factory à la @ServiceHost directive et passé le nom de type CLR de notre fabrique personnalisée comme valeur de l’attribut. Lorsque IIS ou WAS reçoit un message pour ce service, l’infrastructure d’hébergement WCF crée d’abord une instance de ServiceHostFactory, puis instancie l’hôte de service lui-même en appelant ServiceHostFactory.CreateServiceHost().

Exécution de l’exemple

Bien que cet exemple fournisse une implémentation de service et de client entièrement fonctionnelle, le point de l’exemple est d’illustrer comment modifier le comportement d’exécution d’un service à l’aide d’un hôte personnalisé. Procédez comme suit :

Observer l’effet de l’hôte personnalisé

  1. Ouvrez le fichier Web.config du service et observez qu’aucune configuration n’active explicitement les métadonnées pour le service.

  2. Ouvrez le fichier .svc du service et observez que sa @ServiceHost directive contient un attribut Factory qui spécifie le nom d’un ServiceHostFactory personnalisé.

Configurer, générer et exécuter l’exemple

  1. Assurez-vous d’avoir effectué la Procédure d’installation unique pour les exemples Windows Communication Foundation.

  2. Pour générer la solution, suivez les instructions indiquées dans la rubrique Génération des exemples Windows Communication Foundation.

  3. Une fois la solution générée, exécutez Setup.bat pour configurer l’application ServiceModelSamples dans IIS 7.0. Le répertoire ServiceModelSamples doit maintenant apparaître sous la forme d’une application IIS 7.0.

  4. Pour exécuter l’exemple dans une configuration à un ou plusieurs ordinateurs, conformez-vous aux instructions figurant dans la rubrique Exécution des exemples Windows Communication Foundation.

  5. Pour supprimer l’application IIS 7.0, exécutez Cleanup.bat.

Voir aussi