Delen via


Aangepaste servicehost

Het CustomServiceHost-voorbeeld laat zien hoe u een aangepaste afgeleide van de ServiceHost klasse gebruikt om het runtimegedrag van een service te wijzigen. Deze benadering biedt een herbruikbaar alternatief voor het configureren van een groot aantal services op een gemeenschappelijke manier. In het voorbeeld ziet u ook hoe u de ServiceHostFactory klasse gebruikt voor het gebruik van een custom ServiceHost in de hostomgeving Internet Information Services (IIS) of Windows Process Activation Service (WAS).

Over het scenario

Om onbedoelde openbaarmaking van mogelijk gevoelige servicemetagegevens te voorkomen, schakelt de standaardconfiguratie voor WCF-services (Windows Communication Foundation) het publiceren van metagegevens uit. Dit gedrag is standaard beveiligd, maar betekent ook dat u geen hulpprogramma voor het importeren van metagegevens (zoals Svcutil.exe) kunt gebruiken om de clientcode te genereren die is vereist om de service aan te roepen, tenzij het publicatiegedrag voor metagegevens van de service expliciet is ingeschakeld in de configuratie.

Het inschakelen van publicatie van metagegevens voor een groot aantal services omvat het toevoegen van dezelfde configuratie-elementen aan elke afzonderlijke service, wat resulteert in een grote hoeveelheid configuratiegegevens die in wezen hetzelfde zijn. Als alternatief voor het afzonderlijk configureren van elke service is het mogelijk om de imperatieve code te schrijven waarmee metagegevens eenmaal kunnen worden gepubliceerd en die code vervolgens opnieuw kan worden gebruikt in verschillende services. Dit wordt bereikt door een nieuwe klasse te maken die is afgeleid van ServiceHost en de ApplyConfiguration()-methode overschrijft om het publicatiegedrag van metagegevens imperatief toe te voegen.

Belangrijk

Voor de duidelijkheid laat dit voorbeeld zien hoe u een onbeveiligd eindpunt voor het publiceren van metagegevens maakt. Dergelijke eindpunten zijn mogelijk beschikbaar voor anonieme niet-geverifieerde consumenten en zorg moeten worden genomen voordat dergelijke eindpunten worden geïmplementeerd om ervoor te zorgen dat de metagegevens van een service openbaar worden weergegeven.

Een aangepaste ServiceHost implementeren

De ServiceHost klasse bevat verschillende nuttige virtuele methoden die overnames kunnen overschrijven om het runtimegedrag van een service te wijzigen. De () methode leest bijvoorbeeld ApplyConfigurationserviceconfiguratiegegevens uit het configuratiearchief en wijzigt de host ServiceDescription dienovereenkomstig. De standaard implementatie leest de configuratie uit het configuratiebestand van de toepassing. Aangepaste implementaties kunnen () overschrijven ApplyConfigurationom het ServiceDescription gebruik van imperatieve code verder te wijzigen of zelfs het standaardconfiguratiearchief volledig te vervangen. Als u bijvoorbeeld de eindpuntconfiguratie van een service wilt lezen uit een database in plaats van het configuratiebestand van de toepassing.

In dit voorbeeld willen we een aangepaste ServiceHost bouwen waarmee de ServiceMetadataBehavior (waarmee metagegevens kunnen worden gepubliceerd) worden toegevoegd, zelfs als dit gedrag niet expliciet wordt toegevoegd aan het configuratiebestand van de service. Hiervoor maakt u een nieuwe klasse die overgaat van ServiceHost en overschrijft 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)
    }
}

Omdat we geen configuratie willen negeren die is opgegeven in het configuratiebestand van de toepassing, is het eerste dat onze onderdrukking van ApplyConfiguration() de basis-implementatie aanroept. Zodra deze methode is voltooid, kunnen we de ServiceMetadataBehavior beschrijving imperatief toevoegen met behulp van de volgende imperatieve code.

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

Het laatste wat onze ApplyConfiguration() onderdrukking moet doen, is het standaardeindpunt voor metagegevens toevoegen. Standaard wordt er één eindpunt voor metagegevens gemaakt voor elke URI in de BaseAddresses-verzameling van de servicehost.

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

Een aangepaste ServiceHost gebruiken in self-host

Nu we onze aangepaste ServiceHost-implementatie hebben voltooid, kunnen we deze gebruiken om publicatiegedrag voor metagegevens toe te voegen aan elke service door die service binnen een exemplaar van ons SelfDescribingServiceHostte hosten. De volgende code laat zien hoe u deze kunt gebruiken in het self-hostscenario.

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

Onze aangepaste host leest nog steeds de eindpuntconfiguratie van de service uit het configuratiebestand van de toepassing, alsof we de standaardklasse ServiceHost hadden gebruikt om de service te hosten. Omdat we echter de logica hebben toegevoegd voor het inschakelen van publicatie van metagegevens in onze aangepaste host, hoeven we het publicatiegedrag van metagegevens niet meer expliciet in te schakelen in de configuratie. Deze aanpak heeft een duidelijk voordeel wanneer u een toepassing bouwt die verschillende services bevat en u metagegevenspublicatie op elk ervan wilt inschakelen zonder dat u dezelfde configuratie-elementen telkens opnieuw hoeft te schrijven.

Een aangepaste ServiceHost gebruiken in IIS of WAS

Het gebruik van een aangepaste servicehost in self-hostscenario's is eenvoudig, omdat het uw toepassingscode is die uiteindelijk verantwoordelijk is voor het maken en openen van het servicehostexemplaren. In de IIS- of WAS-hostingomgeving wordt de WCF-infrastructuur echter dynamisch geïnstrigeerd op de host van uw service als reactie op binnenkomende berichten. Aangepaste servicehosts kunnen ook worden gebruikt in deze hostingomgeving, maar ze vereisen extra code in de vorm van een ServiceHostFactory. De volgende code toont een afgeleide van ServiceHostFactory die exemplaren van onze aangepaste SelfDescribingServiceHostretourneert.

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

Zoals u ziet, is het implementeren van een aangepaste ServiceHostFactory eenvoudig. Alle aangepaste logica bevindt zich in de ServiceHost-implementatie; de factory retourneert een exemplaar van de afgeleide klasse.

Als u een aangepaste factory wilt gebruiken met een service-implementatie, moeten we enkele aanvullende metagegevens toevoegen aan het .svc-bestand van de service.

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

Hier hebben we een extra Factory kenmerk toegevoegd aan de @ServiceHost instructie en de CLR-typenaam van onze aangepaste factory doorgegeven als de waarde van het kenmerk. Wanneer IIS of WAS een bericht voor deze service ontvangt, maakt de WCF-hostinginfrastructuur eerst een exemplaar van de ServiceHostFactory en wordt vervolgens de servicehost zelf geïnstitueerd door aan te roepen ServiceHostFactory.CreateServiceHost().

Het voorbeeld uitvoeren

Hoewel dit voorbeeld wel een volledig functionele client- en service-implementatie biedt, is het punt van het voorbeeld om te laten zien hoe u het runtimegedrag van een service wijzigt door middel van een aangepaste host. Voer de volgende stappen uit:

Bekijk het effect van de aangepaste host

  1. Open het Web.config-bestand van de service en kijk of er geen configuratie is die expliciet metagegevens voor de service inschakelt.

  2. Open het .svc-bestand van de service en merk op dat de @ServiceHost instructie een Factory-kenmerk bevat dat de naam van een aangepaste ServiceHostFactory aangeeft.

Het voorbeeld instellen, bouwen en uitvoeren

  1. Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.

  2. Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de oplossing te bouwen.

  3. Nadat de oplossing is gebouwd, voert u Setup.bat uit om de ServiceModelSamples-toepassing in IIS 7.0 in te stellen. De map ServiceModelSamples moet nu worden weergegeven als een IIS 7.0-toepassing.

  4. Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.

  5. Als u de IIS 7.0-toepassing wilt verwijderen, voert u Cleanup.bat uit.

Zie ook