Compartir vía


Host de servicio personalizado

El ejemplo CustomServiceHost muestra cómo usar un derivado personalizado de la ServiceHost clase para modificar el comportamiento en tiempo de ejecución de un servicio. Este enfoque proporciona una alternativa reutilizable para configurar un gran número de servicios de una manera común. En el ejemplo también se muestra cómo usar la ServiceHostFactory clase para usar un ServiceHost personalizado en el entorno de hospedaje de Internet Information Services (IIS) o servicio de activación de procesos de Windows (WAS).

Sobre el escenario

Para evitar la divulgación involuntaria de metadatos de servicio potencialmente confidenciales, la configuración predeterminada para los servicios de Windows Communication Foundation (WCF) deshabilita la publicación de metadatos. Este comportamiento es seguro de forma predeterminada, pero también significa que no puede usar una herramienta de importación de metadatos (como Svcutil.exe) para generar el código de cliente necesario para llamar al servicio a menos que el comportamiento de publicación de metadatos del servicio esté habilitado explícitamente en la configuración.

Habilitar la publicación de metadatos para un gran número de servicios implica agregar los mismos elementos de configuración a cada servicio individual, lo que da como resultado una gran cantidad de información de configuración que es básicamente la misma. Como alternativa a configurar cada servicio individualmente, es posible escribir el código imperativo que habilita la publicación de metadatos una vez y, a continuación, reutilizar ese código en varios servicios diferentes. Esto se logra mediante la creación de una nueva clase que deriva del ServiceHost método () e invalida el ApplyConfigurationmétodo () para agregar imperativamente el comportamiento de publicación de metadatos.

Importante

Para mayor claridad, en este ejemplo se muestra cómo crear un punto de conexión de publicación de metadatos no seguros. Estos puntos de conexión pueden estar disponibles para consumidores anónimos no autenticados y se debe tener cuidado antes de implementar estos puntos de conexión para asegurarse de que la divulgación pública de los metadatos de un servicio sea adecuada.

Implementación de un ServiceHost personalizado

La ServiceHost clase expone varios métodos virtuales útiles que los heredadores pueden invalidar para modificar el comportamiento en tiempo de ejecución de un servicio. Por ejemplo, el método ApplyConfiguration() lee información de la configuración de servicio del almacén de configuración y modifica la ServiceDescription del host según corresponda. La implementación predeterminada lee la configuración del archivo de configuración de la aplicación. Las implementaciones personalizadas pueden sobrescribir ApplyConfiguration() para modificar aún más ServiceDescription usando código imperativo o incluso reemplazar por completo el almacén de configuración predeterminado. Por ejemplo, para leer la configuración del punto de conexión de un servicio desde una base de datos en lugar del archivo de configuración de la aplicación.

En este ejemplo, queremos crear un ServiceHost personalizado que agregue ServiceMetadataBehavior (que habilita la publicación de metadatos) incluso si este comportamiento no se agrega explícitamente en el archivo de configuración del servicio. Para ello, cree una nueva clase que herede de ServiceHost e invalide 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)
    }
}

Dado que no queremos omitir ninguna configuración que se haya proporcionado en el archivo de configuración de la aplicación, lo primero que hace nuestra sobreescritura de ApplyConfiguration() es llamar a la implementación base. Una vez completado este método, podemos agregar imperativamente la ServiceMetadataBehavior a la descripción mediante el siguiente código 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;
}

La última cosa que nuestro () invalidadorApplyConfigurationdebe hacer, es agregar el punto de conexión de metadatos predeterminado. Por convención, se crea un punto de conexión de metadatos para cada URI de la colección BaseAddresses del host de servicio.

//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 de un ServiceHost personalizado en el autohospedaje

Ahora que hemos completado nuestra implementación personalizada de ServiceHost, podemos usarla para agregar el comportamiento de publicación de metadatos a cualquier servicio mediante el hospedaje de ese servicio dentro de una instancia de .SelfDescribingServiceHost En el código siguiente se muestra cómo usarlo en el escenario de autohospedado.

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

Nuestro host personalizado sigue leyendo la configuración del punto de conexión del servicio desde el archivo de configuración de la aplicación, como si hubieramos usado la clase predeterminada ServiceHost para hospedar el servicio. Sin embargo, dado que agregamos la lógica para habilitar la publicación de metadatos dentro de nuestro host personalizado, ya no debemos habilitar explícitamente el comportamiento de publicación de metadatos en la configuración. Este enfoque tiene una ventaja al construir una aplicación que contiene varios servicios y desea habilitar la publicación de metadatos en cada uno de ellos sin escribir los mismos elementos de configuración una y otra vez.

Uso de un ServiceHost personalizado en IIS o WAS

El uso de un host de servicio personalizado en escenarios de autohospedado es sencillo, ya que es el código de la aplicación que, en última instancia, es responsable de crear y abrir la instancia de host del servicio. Sin embargo, en el entorno de hospedaje de IIS o WAS, la infraestructura de WCF instancia dinámicamente el host de su servicio en respuesta a los mensajes entrantes. Los hosts de servicio personalizados también se pueden usar en este entorno de hospedaje, pero requieren código adicional en forma de ServiceHostFactory. El código siguiente muestra un derivado de ServiceHostFactory que devuelve instancias de nuestro personalizado 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);
    }
}

Como puede ver, la implementación de un ServiceHostFactory personalizado es sencilla. Toda la lógica personalizada reside dentro de la implementación de ServiceHost; el generador devuelve una instancia de la clase derivada.

Para usar una fábrica personalizada con una implementación de servicio, debemos agregar algunos metadatos adicionales al archivo .svc del servicio.

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

Aquí hemos agregado un atributo adicional Factory a la @ServiceHost directiva y hemos pasado el nombre de tipo CLR de nuestra factoría personalizada como valor del atributo. Cuando IIS o WAS recibe un mensaje para este servicio, la infraestructura de hospedaje de WCF crea primero una instancia de ServiceHostFactory y, a continuación, crea una instancia del propio host del servicio llamando a ServiceHostFactory.CreateServiceHost().

Ejecución del ejemplo

Aunque este ejemplo proporciona una implementación de servicio y cliente totalmente funcional, el punto del ejemplo es ilustrar cómo modificar el comportamiento en tiempo de ejecución de un servicio mediante un host personalizado. Siga estos pasos:

Observe el efecto del host personalizado.

  1. Abra el archivo Web.config del servicio y observe que no hay ninguna configuración que habilite explícitamente los metadatos para el servicio.

  2. Abra el archivo .svc del servicio y observe que su @ServiceHost directiva contiene un atributo Factory que especifica el nombre de un ServiceHostFactory personalizado.

Configuración, compilación y ejecución del ejemplo

  1. Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.

  2. Para compilar la solución, siga las instrucciones que se indican en Compilación de los ejemplos de Windows Communication Foundation.

  3. Una vez compilada la solución, ejecute Setup.bat para configurar la aplicación ServiceModelSamples en IIS 7.0. El directorio ServiceModelSamples debería aparecer ahora como una aplicación de IIS 7.0.

  4. Para ejecutar el ejemplo en una configuración de una máquina única o entre máquinas, siga las instrucciones de Ejecución de los ejemplos de Windows Communication Foundation.

  5. Para quitar la aplicación IIS 7.0, ejecute Cleanup.bat.

Consulte también