martes, 23 de octubre de 2012

WCF - Problemas interoperabilidad con el nodo Wsa:Policy en WSDL

Hemos desarrollado un servicio

WCF

publicado en

IIS

que consumirán clientes de cualquier plataforma (principalmente java) y al configurar desde

IIS

que el servicio solo responderá a peticiones https los clientes java dejan de funcionar (asumimos que han modificado la URL http por https).

Sabemos que

WCF

se basa en el protocolo soap y que W3C define las reglas y estas van evolucionando. Actualmente la versión más reciente del estandar

soap

es la 1.2. En un mundo ideal cuando se plantea un proyecto de este tipo a nivel empresarial ambas partes responsables de cada plataforma deberían establecer el estandar por el que se regirán o si más no debería estar estipulado en algún tipo de documento. En el mundo real no siempre es así y se pueden dar situaciones de "imcompatibilidad" entre servicio y cliente. Este tipo de situaciones suele darse porque

WCF

se basa en el estándar soap 1.2 (W3C) pero el uso de herramientas tanto Java como Microsoft que se basan en soap 1.1 siguen estando bastante extendidas en estos momentos y depedendiendo del escenario es complicado determinar quien debería adaptarse a quien si no está especificado en la definición del proyecto. En este caso por lógica el servidor es 1 y los clientes son N por tanto es más eficiente hacer compatible

WCF

con

soap

1.1 que no obligar a nuestros clientes a adaptarse a 1.2.

Nos alejamos del debate de quien sigue o no el estandar y nos centramos en como solucionar el problema que se plantea en el escenario inicial. Algunos clientes se quejan que hay un nodo más en el

wsdl

que su cliente 1.1 no entiende desde que hemos configurado el tráfico seguro en

IIS

, es el nodo

Wsa:Policy

. La versión 1.2 permite a través de este nodo definir en el documento

wsdl

que tipo de seguridad tiene configurada el servicio a nivel de transporte y mensaje por tanto al configurar https en

IIS

se añaden automáticamente los nodos correspondientes al wsdl.

Una solución es eliminar el nodo problemático, para ello es interesante saber que la clase del Framework que se encarga de generar el documento wsdl de nuestro servicio es

WsdlExporter

y que podemos suplantarla para manipular los nodos del documento

wsdl

que publicamos.

Veamos como hacerlo, en primer lugar crearemos una clase AreaTICWsdlExporter:
namespace areaTIC.WCF
{
    public class AreaTICWsdlExporter : WsdlExporter  
    {
        public override void ExportContract(ContractDescription contract)
        {
            base.ExportContract(contract);
        }

        public override void ExportEndpoint(ServiceEndpoint endpoint)
        {
            base.ExportEndpoint(endpoint);
        }

        public override MetadataSet GetGeneratedMetadata()
        {

            MetadataSet md = base.GetGeneratedMetadata();
            
            //adaptamos wsdl al formato que espera que el cliente java eliminando los nodos que están generando conflicto entre plataformas;

            System.Web.Services.Description.ServiceDescription sd = (System.Web.Services.Description.ServiceDescription)md.MetadataSections[0].Metadata;
            sd.Bindings[0].Extensions.RemoveAt(0);

            if (sd.Bindings.Count > 0)
            {
                if (sd.Bindings[0].Extensions.Count > 0)
                {
                    
                    SoapBinding ele = (SoapBinding)sd.Bindings[0].Extensions[0];
                    ele.Style = SoapBindingStyle.Document;

                    ServiceDescriptionCollection a = base.GeneratedWsdlDocuments;
                    a[0].Extensions.RemoveAt(0);
                }
            }

            return md;
        }
    }
}
El siguiente paso será suplantar

WsdlExporter

en el servicio conflictivo para ello necesitaremos tener control de la instancia

ServiceHost

de nuestro servicio. En este artículo explica como controlar la instacia de

ServiceHost

en IIS usando

ServiceHostFactory

. Una vez tengamos configurado ServiceHostFactory tendremos que añadir en el método CreateServiceHost el código para suplantar

WsdlExporter

por el nuestro personalizado.
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
   switch (serviceType.Name)
   {
       case "ServicioConflictivo":
            ServiceMetadataBehavior smb = customServiceHost.Description.Behaviors.Find();
                    smb.MetadataExporter = new DgestWsdlExporter();
       break;
   }
}
Hasta aquí el artículo, si tenéis alguna duda o queréis hacer algún comentario no os cortéis. También podéis seguir

areaTIC

en las redes sociales, esperamos os haya sido útil.


No hay comentarios:

Publicar un comentario en la entrada