Condividi tramite


Host di servizi personalizzati

Questo esempio dimostra come utilizzare un derivato personalizzato della classe ServiceHost per modificare il comportamento in fase di esecuzione di un servizio. Questo approccio fornisce un'alternativa riutilizzabile alla configurazione tradizionale di un gran numero di servizi. In questo esempio viene inoltre illustrato come impiegare la classe ServiceHostFactory per utilizzare un ServiceHost personalizzato nell'ambiente di hosting Internet Information Services (IIS) o nel servizio di attivazione dei processi di Windows (WAS, Windows Process Activation Service).

Aa395224.Important(it-it,VS.100).gif Nota:
È possibile che gli esempi siano già installati nel computer. Verificare la directory seguente (impostazione predefinita) prima di continuare.

<UnitàInstallazione>:\WF_WCF_Samples

Se questa directory non esiste, vedere la pagina relativa agli esempi di Windows Communication Foundation (WCF) e Windows Workflow Foundation (WF) per .NET Framework 4 per scaricare tutti gli esempi Windows Communication Foundation (WCF) e WF. Questo esempio si trova nella directory seguente.

<UnitàInstallazione>:\WF_WCF_Samples\WCF\Extensibility\Hosting\CustomServiceHost

Informazioni sullo scenario

Per impedire la diffusione accidentale di metadati del servizio potenzialmente riservati, la configurazione predefinita per i servizi Windows Communication Foundation (WCF) disabilita la pubblicazione dei metadati. Questo comportamento è protetto per impostazione predefinita, ma significa inoltre che non è possibile utilizzare uno strumento di importazione di metadati (ad esempio Svcutil.exe) per generare il codice client necessario per chiamare il servizio, a meno che il comportamento del servizio di pubblicazione dei metadati non venga abilitato in modo esplicito in fase di configurazione.

L'abilitazione della pubblicazione dei metadati per un gran numero di servizi comporta l'aggiunta degli stessi elementi di configurazione a ciascun singolo servizio, che produce una quantità elevata di informazioni di configurazione sostanzialmente uguali. Come alternativa alla configurazione di ogni singolo servizio, è possibile scrivere il codice imperativo che consente la pubblicazione dei metadati una volta e riutilizzare quindi tale codice su vari servizi diversi. Ciò viene ottenuto creando una nuova classe che viene derivata da ServiceHost ed esegue l'override del metodo ApplyConfiguration() per aggiungere imperativamente il comportamento di pubblicazione di metadati.

Aa395224.Important(it-it,VS.100).gif Nota:
Per maggior chiarezza, questo esempio illustra come creare un endpoint non protetto per la configurazione di metadati. Tali endpoint sono potenzialmente disponibili per utenti anonimi non autenticati ed è necessario prestare attenzione prima di distribuirli per garantire che la pubblicazione dei metadati di un servizio sia appropriata.

Implementazione di un ServiceHost personalizzato

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

In questo esempio si desidera compilare un ServiceHost personalizzato che aggiunge il ServiceMetadataBehavior, (il quale consente la pubblicazione di metadati) anche se questo comportamento non viene aggiunto in modo esplicito nel file di configurazione del servizio. Per ottenere questo risultato, viene creata una nuova classe che eredita da ServiceHost ed esegue l'override di 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é ogni configurazione fornita nel file di configurazione dell'applicazione non va ignorata, la prima operazione di override di ApplyConfiguration() è chiamare l'implementazione di base. Dopo che questo metodo è stato completato, è possibile aggiungere in modo imperativo ServiceMetadataBehavior alla descrizione utilizzando il codice imperativo seguente.

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 don't have any work to do.
    return;
}

L'ultima operazione dell'override di ApplyConfiguration() è aggiungere l'endpoint di metadati predefinito. Per convenzione, viene creato uno endpoint di metadati per ciascun URI nella raccolta BaseAddresses del 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");
    }
}

Utilizzo di un ServiceHost personalizzato in host indipendente

Ora che è stata completata l'implementazione personalizzata di ServiceHost, è possibile utilizzarlo per aggiungere il comportamento di pubblicazione dei metadati a qualsiasi servizio ospitando tale servizio all'interno di un'istanza di SelfDescribingServiceHost. Nell'esempio di codice seguente viene illustrato come utilizzarlo nello scenario di host indipendente.

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

L'host personalizzato legge comunque la configurazione dell'endpoint del servizio dal file di configurazione dell'applicazione, come se fosse stata utilizzata la classe ServiceHost predefinita 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 offre un vantaggio evidente quando si compila un'applicazione che contiene diversi servizi e si desidera abilitare la pubblicazione dei metadati su ognuno di essi senza riscrivere ripetutamente gli stessi elementi di configurazione.

Utilizzo di un ServiceHost personalizzato in IIS e WAS

L'utilizzo di un host del servizio personalizzato in scenari di host indipendente è semplice in quanto spetta fondamentalmente al codice dell'applicazione la responsabilità di creare e aprire l'istanza dell'host del servizio. Nell'ambiente di hosting di IIS o WAS, tuttavia, l'infrastruttura WCF crea in modo dinamico istanze dell'host del servizio in risposta ai messaggi in arrivo. Gli host del servizio personalizzati possono essere utilizzati anche in questo ambiente di hosting, ma richiedono del codice aggiuntivo nel modulo di un ServiceHostFactory. Nel codice seguente è illustrato un derivato di ServiceHostFactory che restituisce istanze del 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 è possibile vedere, l'implementazione di un ServiceHostFactory personalizzato è molto semplice. Tutta la logica personalizzata risiede all'interno dell'implementazione ServiceHost; la factory restituisce un'istanza della classe derivata.

Per utilizzare una factory personalizzata con un'implementazione del servizio, è necessario aggiungere altri metadati al file con estensione svc del servizio.

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

Qui è stato aggiunto un ulteriore attributo Factory alla direttiva @ServiceHost al quale è stato passato come valore il nome del tipo CLR della factory personalizzata. Quando IIS o WAS riceve un messaggio per questo servizio, l'infrastruttura di hosting di WCF prima crea un'istanza di ServiceHostFactory e quindi attiva un'istanza dell'host del servizio stesso chiamando ServiceHostFactory.CreateServiceHost().

Esecuzione dell'esempio

Anche se questo esempio fornisce un'implementazione del client e del servizio completamente funzionale, l'obiettivo dell'esempio è illustrare come modificare il comportamento in fase di esecuzione di un servizio per mezzo di un host personalizzato eseguendo le operazioni seguenti:

Per osservare l'effetto dell'host personalizzato

  1. Aprire il file Web.config del servizio e osservare come non vi sia alcuna configurazione che abilita in modo esplicito i metadati per il servizio.

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

Per impostare, compilare ed eseguire l'esempio

  1. Verificare di avere eseguito la Procedura di installazione singola per gli esempi di Windows Communication Foundation.

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

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

  4. Per eseguire l'esempio in una configurazione con un solo computer o tra computer diversi, seguire le istruzioni in Running the Windows Communication Foundation Samples.

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

Vedere anche

Attività

Procedura: ospitare un servizio WCF in IIS