Condividi tramite


Servizio host personalizzato

L'esempio CustomServiceHost illustra come usare una derivata personalizzata della ServiceHost classe per modificare il comportamento di runtime di un servizio. Questo approccio offre un'alternativa riutilizzabile alla configurazione di un numero elevato di servizi in modo comune. L'esempio illustra anche come usare la ServiceHostFactory classe per usare un ServiceHost personalizzato nell'ambiente di hosting INTERNET Information Services (IIS) o del servizio di attivazione dei processi Windows (WAS).

Informazioni sullo scenario

Per impedire la divulgazione involontaria dei metadati del servizio potenzialmente sensibili, la configurazione predefinita per i servizi Windows Communication Foundation (WCF) disabilita la pubblicazione dei metadati. Questo comportamento è sicuro per impostazione predefinita, ma significa anche che non è possibile usare uno strumento di importazione dei metadati (ad esempio Svcutil.exe) per generare il codice client necessario per chiamare il servizio, a meno che il comportamento di pubblicazione dei metadati del servizio non sia abilitato in modo esplicito nella configurazione.

L'abilitazione della pubblicazione dei metadati per un numero elevato di servizi comporta l'aggiunta degli stessi elementi di configurazione a ogni singolo servizio, che comporta una grande quantità di informazioni di configurazione essenzialmente uguali. In alternativa alla configurazione di ogni servizio singolarmente, è possibile scrivere il codice imperativo che consente la pubblicazione dei metadati una sola volta e quindi riutilizzare tale codice in diversi servizi. Questa operazione viene eseguita creando una nuova classe che deriva da ServiceHost ed esegue l'override del ApplyConfigurationmetodo () per aggiungere in modo imperativo il comportamento di pubblicazione dei metadati.

Importante

Per maggiore chiarezza, questo esempio illustra come creare un endpoint di pubblicazione di metadati non protetti. Tali endpoint sono potenzialmente disponibili per i consumer anonimi non autenticati e occorre prestare attenzione prima di distribuire tali endpoint per garantire che i metadati di un servizio siano appropriati pubblicamente.

Implementazione di un ServiceHost personalizzato

La ServiceHost classe espone diversi metodi virtuali utili che gli eredi possono eseguire l'override per modificare il comportamento di runtime di un servizio. Ad esempio, il ApplyConfigurationmetodo () legge le informazioni di configurazione del servizio dall'archivio di configurazione e modifica di conseguenza l'host ServiceDescription . L'implementazione predefinita legge la configurazione dal file di configurazione dell'applicazione. Le implementazioni personalizzate possono sovrascrivere ApplyConfiguration() per modificare ulteriormente ServiceDescription utilizzando codice imperativo o persino sostituire completamente l'archivio di configurazione predefinito. Ad esempio, per leggere la configurazione dell'endpoint di un servizio da un database anziché dal file di configurazione dell'applicazione.

In questo esempio si vuole compilare un ServiceHost personalizzato che aggiunge ServiceMetadataBehavior (che abilita la pubblicazione dei metadati) anche se questo comportamento non viene aggiunto in modo esplicito nel file di configurazione del servizio. A tale scopo, creare una nuova classe che eredita da ServiceHost ed esegue l'override 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)
    }
}

Poiché non vogliamo ignorare alcuna configurazione fornita nel file di configurazione dell'applicazione, la prima operazione che il nostro override di ApplyConfiguration() esegue è chiamare l'implementazione base. Al termine di questo metodo, possiamo aggiungere in modo imperativo ServiceMetadataBehavior alla descrizione utilizzando il seguente codice imperativo.

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

L'ultima cosa che il nostro ApplyConfiguration() override deve fare è aggiungere l'endpoint dei metadati predefinito. Per convenzione, viene creato un endpoint di metadati per ogni URI nella raccolta BaseAddresses dell'host del servizio.

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

Uso di un ServiceHost personalizzato in self-host

Ora che è stata completata l'implementazione personalizzata di ServiceHost, è possibile usarla per aggiungere il comportamento di pubblicazione dei metadati a qualsiasi servizio ospitando tale servizio all'interno di un'istanza di SelfDescribingServiceHost. Il codice seguente illustra come usarlo nello scenario self-host.

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

L'host personalizzato legge ancora la configurazione dell'endpoint del servizio dal file di configurazione dell'applicazione, come se fosse stata usata la classe predefinita ServiceHost per ospitare il servizio. Tuttavia, poiché è stata aggiunta la logica per abilitare la pubblicazione dei metadati all'interno dell'host personalizzato, non è più necessario abilitare in modo esplicito il comportamento di pubblicazione dei metadati nella configurazione. Questo approccio presenta un vantaggio distinto quando si compila un'applicazione che contiene diversi servizi e si vuole abilitare la pubblicazione dei metadati in ognuno di essi senza scrivere gli stessi elementi di configurazione oltre e oltre.

Uso di un ServiceHost personalizzato in IIS o WAS

L'uso di un host del servizio personalizzato in scenari self-host è semplice, perché è il codice dell'applicazione responsabile della creazione e dell'apertura dell'istanza host del servizio. Nell'ambiente di hosting IIS o WAS, tuttavia, l'infrastruttura WCF sta istanziando dinamicamente l'host del servizio in risposta ai messaggi in arrivo. Gli host di servizio personalizzati possono essere usati anche in questo ambiente host, ma richiedono codice aggiuntivo sotto forma di ServiceHostFactory. Il codice seguente mostra una classe derivata di ServiceHostFactory che restituisce istanze del nostro SelfDescribingServiceHost personalizzato.

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

Come si può notare, l'implementazione di un ServiceHostFactory personalizzato è semplice. Tutta la logica personalizzata risiede all'interno dell'implementazione di ServiceHost; la factory restituisce un'istanza della classe derivata.

Per usare una factory personalizzata con un'implementazione del servizio, è necessario aggiungere alcuni metadati al file .svc del servizio.

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

Abbiamo aggiunto un attributo aggiuntivo Factory alla direttiva @ServiceHost e abbiamo passato il nome del tipo CLR della nostra factory personalizzata come valore dell'attributo. Quando IIS o WAS riceve un messaggio per questo servizio, l'infrastruttura di hosting WCF crea innanzitutto un'istanza di ServiceHostFactory e quindi crea un'istanza dell'host del servizio chiamando ServiceHostFactory.CreateServiceHost().

Esecuzione dell'esempio

Anche se questo esempio fornisce un'implementazione del client e del servizio completamente funzionale, il punto dell'esempio consiste nell'illustrare come modificare il comportamento di runtime di un servizio tramite un host personalizzato. Seguire questa procedura:

Osservare l'effetto dell'host personalizzato

  1. Aprire il file di Web.config del servizio e osservare che non è presente alcuna configurazione che abilita i metadati per il servizio in modo esplicito.

  2. Aprire il file con estensione svc del servizio e osservare che la relativa @ServiceHost direttiva contiene un attributo Factory che specifica il nome di un oggetto ServiceHostFactory personalizzato.

Configurare, compilare ed eseguire l'esempio

  1. Assicurati di aver eseguito la procedura di installazione di One-Time per gli esempi di Windows Communication Foundation.

  2. Per compilare la soluzione, seguire le istruzioni riportate in Compilazione degli esempi di Windows Communication Foundation.

  3. Dopo aver compilato la soluzione, eseguire Setup.bat per configurare l'applicazione ServiceModelSamples in IIS 7.0. La directory ServiceModelSamples dovrebbe ora essere visualizzata come applicazione IIS 7.0.

  4. Per eseguire l'esempio in una configurazione con computer singolo o incrociato, seguire le istruzioni riportate in Esecuzione degli esempi di Windows Communication Foundation.

  5. Per rimuovere l'applicazione IIS 7.0, eseguire Cleanup.bat.

Vedere anche