WCF – El caso del wsdl con xsd:import schemalocation que no puede ser interpretado desde clientes PHP
o
El caso del wsdl con referencias externas que no puede ser usado en PHP
Este caso esta relacionado con el caso revisado en el artículo:
WCF – El caso del wsdl con referencias externas apuntando al servidor local
Por lo cual es otra anecdota de casos de consultoria
.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co , como ya sabemos cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde únicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
En otra oportunidad analizaremos el contenido de esas url, pero no es nada complejo.
El problema reside en que muchos clientes SOAP, sobre todo de tecnologías como PHP, no son capaces de interpretar este tipo de schemas xsd dentro de un wsdl, por lo cual la tarea de consumir el servicio WCF en ocasiones complicada
Los clientes SOAP para PHP en su mayoría requieren que el wsdl incorpore TODAS las especificaciones dentro de si, no soportan referencias externas, así que hay que 'aplanar' el wsdl para que todo quede en el mismo archivo.
Hay dos formas de solucionar este problema
- Forma fácil: Utiliza Framework 4.5, en el cual por defecto WCF incluye la opción de consultar el wsd así:http://my.webpage.com.co/MyService.svc?singlewsdl ,lo que es el mismo wsdl de siempre pero sin referencias externas, TODO EN UNO.
- Sino puedes pasarte a Framework 4.5, lo cual es muy probable en escenario empresariales, entonces continua leyendo este artículo.
Esta tarea requiere realizar algunas modificaciones a nivel de behaviors y endpoints, de hecho debes crear nuevos behaviors, no es nada del otro mundo, pero como todo, requiere tiempo, aprendizaje, pruebas etc. y si estas de afán multiplica este efecto por cien.
Por suerte existen personas que les gusta compartir conocimiento y este caso no es la excepción, en CodePlex, encontramos un proyecto llamado:
WCFExtras
Cuyo lema es: "WCF Soap Header support, Xml comments to WSDL annotation and more", a que te suena muy intereante! 
Bien, se los dejo como tema para revisar, este artículo no trata de conocer a fondo WCFExtras, tan solo una pequeña parte para solucionar nuestro lio.
Una de las funcionalidades de WCFExtras es "Single WSDL file", les suena familiar? en efecto esta funcionalidad nos permite 'aplanar' el wsdl para que no tenga referencias externas sino todo incorporado de una vez en un mismo archivo, justo lo que necesitamos.
Cómo se soluciona?
Lo primero que debemos hacer es bajar WCFExtras y compilar la dll, la agregamos al proyecto donde creamos nuestro servicio.
Seguidamente editamos el archivo app.config y adicionamos la siguiente extensión de behaviors
|
1
2
3
4
5
6
7
|
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
|
Esto ya nos garantiza que podemos acceder a los nuevos behaviors incorporados con WCFExtras. Así que ahora solo basta utilizarlos para nuestro caso puntual, esta es la forma más sencilla de generar un wsdl 'aplanado', simplemente agregamos un behavior en endpointBehaviors, el tipo del behavior es wsdlExtensions y le pasamos como parámetro singleFile=true
|
1
2
3
4
5
6
7
8
|
<behaviors>
<endpointBehaviors>
<behavior>
<wsdlExtensions singleFile="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
</behaviors>
|
Eso es todo, hora de consultar el wsdl de nuevo y... ya no tenemos nada parecido a lo que vimos más arriba, en su lugar encontramos algo como esto inclusive para los tipos complejos:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<wsdl:types>
<xs:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
<xs:element name="anyType"
nillable="true"
type="xs:anyType"/>
<xs:element name="anyURI"
nillable="true"
type="xs:anyURI"/>
<xs:element name="boolean"
nillable="true"
type="xs:boolean"/>
<xs:element name="byte"
nillable="true"
type="xs:byte"/>
<xs:element name="dateTime"
nillable="true"
type="xs:dateTime"/>
</xs:schema>
</wsdl:types>
|
TODA la información ha sido consolidada en el mismo wsdl.
El caso del wsdl con xsd:import schemalocation apuntando a la url local en lugar de la pública
Dentro de mis labores como Arquitecto y Consultor me he encontrado con este caso que es digno de mencionar, y aunque algunos se sorprendan creanme que este escenario es más comun de lo que imaginan.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co ,cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde unicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
Vieron lo que sucede? las URL de los xsd no estan apuntando a http://my.webpage.com.co sino a la direccion de la red local http://myLocalServer.webpage.com.co .
A primera impresión es un problema de configuración del WCF, y en efecto al modificar algunos parametros podemos hacer que las URL del wsdl aparezcan solo como http://myLocalServer/MyService.svc , incluso podemos modificar la re esddfritura de URL desde el app.comfig para redireccionar este tipo de peticion es de manera correcta,pero no es un problema fácil de solucionar.
En algunas compañías lo que optan por hacer es modificar su firewall y/o configuracion de dominio público para que permita redireccionar las peticiones a la URL adecuada.
Aunque a primera impresión es un problema de WCF, la realidad es otra. Es un problema en la configuración de IIS.
WCF le pide al web server la dirección host principal para poder armar las rutas a los xsd, y allí es donde IIS le envia el nombre de la máquina local. Pero seamos justos... tampoco es un error de IIS.
Imaginate que tienes un servicio que solo se ejecuta dentro de tu empresa, en ese contexto IIS debe devolverte el nombre local de la máquina, ahora imagina que ese mismo servidor lo conectas a una IP púbica, es decir sin dejar de soportar aúnla URL corporativa, cuando WCF le pregunte al IIS el nombre del host le devolera el nombre local.
Cómo solucionarlo, como los profesionales?
Una de las ventajas que tiene haber iniciado mi carrera como profesional de IT antes de ser developer, es que me permite recordar que NO TODO lo debes resolver por código. IIS nos permite configurar los host names para cada sitio.
Vamos a nuestro sitio donde se publico el WCF, clic derecho propiedades, pestaña Web Site y damos clic en el boton advanced.

Damos doble clic sobre el host por defecto y lo editamos, dejando el nombre público correcto de nuestro servidor.

Y eso es todo! ahora las URL de los xsd referenciados desde el wsdl estan direccionadas correctamente.