Benutzerdefinierter DiensthostCustom Service Host

In diesem Beispiel wird veranschaulicht, wie mit einer benutzerdefinierten Ableitung der ServiceHost-Klasse das Laufzeitverhalten eines Diensts geändert wird.This sample demonstrates how to use a custom derivative of the ServiceHost class to alter the run-time behavior of a service. Dieser Ansatz stellt eine wiederverwendbare Alternative zum Konfigurieren einer großen Anzahl von Diensten auf die übliche Weise war.This approach provides a reusable alternative to configuring a large number of services in a common way. Außerdem zeigt das Beispiel, wie mithilfe der ServiceHostFactory-Klasse ein benutzerdefinierter ServiceHost in der IIS-(Internet Information Services, Internetinformationsdienste-) oder WAS-(Windows Process Activation Service-)Hostumgebung verwendet wird.The sample also demonstrates how to use the ServiceHostFactory class to use a custom ServiceHost in the Internet Information Services (IIS) or Windows Process Activation Service (WAS) hosting environment.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Extensibility\Hosting\CustomServiceHost

Informationen über das SzenarioAbout the Scenario

Um unbeabsichtigtes Offenlegen möglicherweise vertraulichen Dienstmetadaten zu verhindern, deaktiviert die Standardkonfiguration für Windows Communication Foundation (WCF)-Dienste die Metadatenveröffentlichung.To prevent unintentional disclosure of potentially sensitive service metadata, the default configuration for Windows Communication Foundation (WCF) services disables metadata publishing. Dieses Verhalten ist in der Standardeinstellung sicher, bedeutet aber auch, dass man den zum Aufrufen des Diensts erforderlichen Clientcode nicht mithilfe eines Tools zum Importieren von Metadaten (wie Svcutil.exe) generieren kann. Dies ist nur dann möglich, wenn das Verhalten des Diensts zum Veröffentlichen von Metadaten in der Konfiguration explizit aktiviert ist.This behavior is secure by default, but also means that you cannot use a metadata import tool (such as Svcutil.exe) to generate the client code required to call the service unless the service’s metadata publishing behavior is explicitly enabled in configuration.

Wenn die Metadatenveröffentlichung für eine große Anzahl von Diensten aktiviert wird, werden jedem einzelnen Dienst die gleichen Konfigurationselemente hinzugefügt. Dies führt zu einer großen Anzahl von Konfigurationsinformationen, die weitgehend identisch sind.Enabling metadata publishing for a large number of services involves adding the same configuration elements to each individual service, which results in a large amount of configuration information that is essentially the same. Anstatt jeden Dienst einzeln zu konfigurieren, ist es möglich, imperativen Code zu schreiben, der eine einmalige Veröffentlichung der Metadaten ermöglicht. Anschließend kann dieser Code für mehrere unterschiedliche Dienste verwendet werden.As an alternative to configuring each service individually, it is possible to write the imperative code that enables metadata publishing once and then reuse that code across several different services. Zu diesem Zweck wird eine neue Klasse erstellt, die von ServiceHost abgeleitet wird und die ApplyConfiguration()-Methode überschreibt, um das Metadatenveröffentlichungsverhalten imperativ hinzuzufügen.This is accomplished by creating a new class that derives from ServiceHost and overrides the ApplyConfiguration() method to imperatively add the metadata publishing behavior.

Wichtig

Beachten Sie, dass in diesem Beispiel die Erstellung eines ungesicherten Metadaten-Veröffentlichungsendpunkts veranschaulicht wird.For clarity, this sample demonstrates how to create an unsecured metadata publishing endpoint. Solche Endpunkte können für anonyme, nicht authentifizierte Benutzer möglicherweise verfügbar sein. Daher muss beim Bereitstellen solcher Endpunkte sorgfältig darauf geachtet werden, dass das Öffentlichmachen von Metadaten eines Diensts sachgerecht erfolgt.Such endpoints are potentially available to anonymous unauthenticated consumers and care must be taken before deploying such endpoints to ensure that publicly disclosing a service’s metadata is appropriate.

Implementieren eines benutzerdefinierten DiensthostsImplementing a Custom ServiceHost

Die ServiceHost-Klasse macht mehrere hilfreiche virtuelle Methoden verfügbar, die von Erben überschrieben werden können, um das Laufzeitverhalten eines Diensts zu ändern.The ServiceHost class exposes several useful virtual methods that inheritors can override to alter the run-time behavior of a service. Beispielsweise liest die ApplyConfiguration()-Methode die Dienstkonfigurationsinformationen aus dem Konfigurationsspeicher und ändert die ServiceDescription des Diensts entsprechend.For example, the ApplyConfiguration() method reads service configuration information from the configuration store and alters the host's ServiceDescription accordingly. Die Standardimplementierung liest die Konfiguration aus der Konfigurationsdatei der Anwendung.The default implementation reads configuration from the application’s configuration file. Die benutzerdefinierte Implementierung kann ApplyConfiguration() überschreiben, um die ServiceDescription mithilfe von imperativem Code zu ändern oder den Standardkonfigurationsspeicher vollständig zu ersetzen,Custom implementations can override ApplyConfiguration() to further alter the ServiceDescription using imperative code or even replace the default configuration store entirely. z.B. um die Endpunktkonfiguration eines Diensts aus einer Datenbank zu lesen, anstatt aus der Konfigurationsdatei der Anwendung.For example, to read a service’s endpoint configuration from a database instead of the application’s configuration file.

In diesem Beispiel soll ein benutzerdefinierter Diensthost erstellt werden, der das ServiceMetadataBehavior hinzufügt (das die Veröffentlichung von Metadaten ermöglicht), selbst wenn dieses Verhalten in der Konfigurationsdatei des Diensts nicht ausdrücklich hinzugefügt wurde.In this sample, we want to build a custom ServiceHost that adds the ServiceMetadataBehavior, (which enables metadata publishing), even if this behavior is not explicitly added in the service’s configuration file. Zu diesem Zweck erstellen wir eine neue Klasse, die von ServiceHost erbt und ApplyConfiguration() überschreibt.To accomplish this, we create a new class that inherits from ServiceHost and overrides 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)  
    }  
}  

Da die Konfigurationen in der Konfigurationsdatei der Anwendung nicht ignoriert werden sollen, wird beim Überschreiben von ApplyConfiguration() zuerst die Basisimplementierung aufgerufen.Because we do not want to ignore any configuration that has been provided in the application’s configuration file, the first thing our override of ApplyConfiguration() does is call the base implementation. Nach der Fertigstellung dieser Methode kann das ServiceMetadataBehavior der Beschreibung imperativ mithilfe des folgenden imperativen Codes hinzugefügt werden.Once this method completes, we can imperatively add the ServiceMetadataBehavior to the description using the following imperative 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;  
}  

Die letzte Aufgabe, die beim Überschreiben von ApplyConfiguration() ausgeführt werden muss, ist das Hinzufügen des Standardmetadatenendpunkts.The last thing our ApplyConfiguration() override must do is add the default metadata endpoint. Entsprechend der Konvention wird für jeden URI in der BaseAddresses-Auflistung des Diensthosts ein Metadatenendpunkt erstellt.By convention, one metadata endpoint is created for each URI in the service host’s BaseAddresses collection.

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

Verwenden eines benutzerdefinierten Diensthosts bei SelbsthostUsing a custom ServiceHost in self-host

Nachdem wir nun die Implementierung des benutzerdefinierten Diensthosts fertig gestellt haben, können wird diese verwenden, um einem beliebigen Dienst Metadatenveröffentlichungsverhalten hinzuzufügen, indem dieser Dienst innerhalb einer Instanz von SelfDescribingServiceHost gehostet wird.Now that we have completed our custom ServiceHost implementation, we can use it to add metadata publishing behavior to any service by hosting that service inside of an instance of our SelfDescribingServiceHost. Im folgenden Code wird gezeigt, wie diese im Selbsthostszenario verwendet wird.The following code shows how to use it in the self-host scenario.

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

Der benutzerdefinierte Host liest die Endpunktkonfiguration des Diensts nach wie vor aus der Konfigurationsdatei der Anwendung, so als wäre die ServiceHost-Standardklasse zum Hosten des Diensts verwendet worden.Our custom host still reads the service’s endpoint configuration from the application’s configuration file, just as if we had used the default ServiceHost class to host the service. Da jedoch in dem benutzerdefinierten Host die Logik für die Aktivierung der Metadatenveröffentlichung hinzugefügt wurde, muss das Metadatenveröffentlichungsverhalten nicht mehr explizit in der Konfiguration aktiviert werden.However, because we added the logic to enable metadata publishing inside of our custom host, we no longer must explicitly enable the metadata publishing behavior in configuration. Dieser Ansatz bietet vor allem dann Vorteile, wenn Sie eine Anwendung erstellen, die mehrere Dienste enthält, und Sie die Metadatenveröffentlichung auf allen diesen Diensten aktivieren möchten, ohne jedes Mal die gleichen Konfigurationselemente schreiben zu müssen.This approach has a distinct advantage when you are building an application that contains several services and you want to enable metadata publishing on each of them without writing the same configuration elements over and over.

Verwenden eines benutzerdefinierten Diensthosts in IIS oder WASUsing a Custom ServiceHost in IIS or WAS

Die Verwendung eines benutzerdefinierten Diensthosts in einem Selbsthostszenario ist einfach, da ausschließlich Ihr eigener Anwendungscode für die Erstellung und Öffnung der Diensthostinstanz verantwortlich ist.Using a custom service host in self-host scenarios is straightforward, because it is your application code that is ultimately responsible for creating and opening the service host instance. In der IIS- oder WAS-Hostingumgebung ist jedoch die WCF-Infrastruktur dynamisch den Host Ihres Diensts als Antwort auf eingehende Nachrichten instanziieren.In the IIS or WAS hosting environment, however, the WCF infrastructure is dynamically instantiating your service’s host in response to incoming messages. Es können in dieser Hostingumgebung auch benutzerdefinierte Diensthosts verwendet werden, für diese ist jedoch zusätzlicher Code in Form einer ServiceHostFactory erforderlich.Custom service hosts can also be used in this hosting environment, but they require some additional code in the form of a ServiceHostFactory. Im folgenden Code wird eine Ableitung von ServiceHostFactory dargestellt, die Instanzen des benutzerdefinierten SelfDescribingServiceHost zurückgibt.The following code shows a derivative of ServiceHostFactory that returns instances of our custom 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);  
    }  
}  

Wie Sie sehen können, ist die Implementierung einer benutzerdefinierten ServiceHostFactory sehr einfach.As you can see, implementing a custom ServiceHostFactory is very straightforward. Die gesamte benutzerdefinierte Logik befindet sich in der Implementierung des Diensthosts, und die Factory gibt eine Instanz der abgeleiteten Klasse zurück.All of the custom logic resides inside of the ServiceHost implementation; the factory returns an instance of the derived class.

Um eine benutzerdefinierte Factory mit einer Dienstimplementierung zu verwenden, müssen der .svc-Datei des Diensts einige zusätzlich Metadaten hinzugefügt werden.To use a custom factory with a service implementation, we must add some additional metadata to the service’s .svc file.

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

Hier wurde der Factory-Direktive ein zusätzliches @ServiceHost-Attribut hinzugefügt, und der CLR-Typname der benutzerdefinierten Factory wurde als Attributwert übergeben.Here we have added an additional Factory attribute to the @ServiceHost directive, and passed the CLR type name of our custom factory as the attribute’s value. Wenn IIS oder WAS eine Nachricht für diesen Dienst empfängt, wird der WCF--Hostinfrastruktur erstellt zunächst eine Instanz der ServiceHostFactory und instanziiert anschließend durch Aufrufen den Diensthost selbst ServiceHostFactory.CreateServiceHost().When IIS or WAS receives a message for this service, the WCF hosting infrastructure first creates an instance of the ServiceHostFactory and then instantiate the service host itself by calling ServiceHostFactory.CreateServiceHost().

Ausführen des BeispielsRunning the Sample

Auch wenn dieses Beispiel einen voll funktionsfähigen Client und Dienstimplementierung bereitstellt, ist das Ziel des Beispiels, die Änderung des Laufzeitverhaltens des Diensts mithilfe eines benutzerdefinierten Hosts zu veranschaulichen. Führen Sie die folgenden Schritte aus:Although this sample does provide a fully-functional client and service implementation, the point of the sample is to illustrate how to alter a service’s run-time behavior by means of a custom host., do the following steps:

So beobachten Sie den Effekt des benutzerdefinierten HostsTo observe the effect of the custom host

  1. Wenn Sie die Datei "Web.config" des Diensts öffnen, stellen Sie fest, dass keine Konfiguration explizit die Metadaten für den Dienst aktiviert.Open the service’s Web.config file and observe that there is no configuration explicitly enabling metadata for the service.

  2. Öffnen Sie die SVC Datei, und beachten Sie, dass seine @ServiceHost Richtlinie enthält eine factoryattribut, das den Namen der benutzerdefinierten ServiceHostFactory angibt.Open the service’s .svc file and observe that its @ServiceHost directive contains a Factory attribute that specifies the name of a custom ServiceHostFactory.

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, build, and run the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Nachdem die Projektmappe erstellt wurde, führen Sie Setup.bat aus, um die ServiceModelSamples-Anwendung in IIS 7.0IIS 7.0 einzurichten.After the solution has been built, run Setup.bat to set up the ServiceModelSamples Application in IIS 7.0IIS 7.0. Das Verzeichnis ServiceModelSamples sollte jetzt als IIS 7.0IIS 7.0-Anwendung angezeigt werden.The ServiceModelSamples directory should now appear as an IIS 7.0IIS 7.0 Application.

  4. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

  5. Um die Anwendung IIS 7.0IIS 7.0 zu entfernen, müssen Sie Cleanup.bat ausführen.To remove the IIS 7.0IIS 7.0 application, run Cleanup.bat.

Siehe auchSee Also

How to: Host a WCF Service in IIS (Vorgehensweise: Hosten eines WCF-Diensts in IIS)How to: Host a WCF Service in IIS