InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
También puedes ver ...
SubVersion y Visual Studio
Usuarios del sistema en Windows (servicios)
Templates css para web
IIsAdmin.NET - Como tener mas de un sitio web en IIS en Windows XP
SoapUI - Excelente aplicacion para probar Web Services
IIS 6 y la Autenticacion integrada
Compresión por gzip y deflate
Iconlook y Ajaxinfo - Imagenes para tus aplicaciones
Un control interesante y gratuito para aplicaciones ASP.NET: FreeTextBox!
Aprende Ajax desde cero


Ejecutar un servicio WCF desde PHP

En un proyecto reciente he tenido que crear un web service con WCF para que sea consumido por un programa cliente escrito en PHP.

Por supuesto, el servicio lo he programado con .NET. En concreto he realizado un servicio de WCF (Windows Communication Foundation) con enlace por http hospedado en un servidor IIS. Es decir, un web service.

Se da el caso de que el programa es un servicio especifico para una empresa diferente a la que trabajo yo, donde desarrollan exclusivamente en PHP. Yo hice mi progroma tranquilamente, el enlace lo defini como wsHttpBinding (estandart actual), y lo probe con un cliente .NET y con un cliente Java - SoapUI -, funcionando a la perfeccion en ambos casos.

Pero el servicio era para ser consumido desde PHP ... Como me gusta probar bien las cosas - por mucho que los web service sean estandares maravillosos y que si funciona con un cliente .NET o Java debe funcionar en PHP, Phyton o RoR -, me descargue mi Aptana para probar el servicio. Realice un sencillo programilla para probar mi servicio y no son pocos los problemas que encontre.

Para trabajar con PHP y web services tenemos dos posibilidades:

  1. La librería nuSOAP - se trata de una librería open source que debemos descargar y referenciar en nuestro proyecto.
  2. Soporte nativo de PHP para web service. Es un soporte experimental y solo está disponible para version 5 o superior.

Mi primera opcion fue la librería nuSOAP - es la que usaba la otra empresa y eso de "experimental" en el soporte nativo me daba "yuyu", mucho "yuyu".

Con la librería nuSOAP no fui capaz de enviar parametros de tipo complejo - es decir clases como parámetros del web service -, asi que finalmente utilice el soporte nativo de PHP 5. 

Como no son pocos los aspectos a tener en cuenta vamos a ver un ejemplo completo que funciona. La idea es simple, vamos a crear un servicio para guardar datos de "personas" en archivos Xml.

He utilizado Visual Studio 2008 - .NET Framework 3.5 SP1 -  y Aptana con PHP 5 como entornos de desarrollo.

El servicio de WCF

Lo primero debemos crear con Visual Studio una nueva Solucion en blanco. Agregamos ahora un proyecto de tipo "Web - Servicio de WCF" al que llamamos WcfPersonasService.

El servicio va a ser muy simple, con un único método para añadir una persona , al que llamamos AddPersona y que recibe como único parámetro un objeto Persona.

Lo primero definimos la interface del servicio:

 

[ServiceContract]

public interface IWcfPersonasService

{

[OperationContract]

AddPersonaResult AddPersona(Persona persona);

}

Hemos decorado la iterface con ServiceContract y el método con OperationContract para que se exponga correctamente en la fachada del servicio.

Como podemos ver el método AddPersona recibe un único paramétro de tipo Persona  y devuelve un AddPersonaResult  - todos tipos complejos (clases), por lo que no podemos utilizar nuSOAP - o al menos yo no he sido capaz :-(

Ahora necesitamos las clases necesarias para el servicio, Persona - que a su vez requiere de Documento - y AddPersonaResult .

 

[DataContract]

public class Persona

{

[DataMember]

public string Nombre { get; set; }

 

[DataMember]

public string PrimerApellido { get; set; }

 

[DataMember]

public string SegundoApellido { get; set; }

 

[DataMember]

public Documento Documento { get; set; }

}

 

[DataContract]

public class AddPersonaResult

{

[DataMember]

public string ReturnCode { get; set; }

 

[DataMember]

public string Mensaje { get; set; }

}

 

[DataContract]

public class Documento

{

[DataMember]

public string Tipo { get; set; }

[DataMember]

public string Numero { get; set; }

[DataMember]

public string Letra { get; set; }

}

Decoramos las clases DataContract y DataMember para que se expongan correctamente a través del servicio.

La implementacion.

A continuacion escribimos nuestra clase para implementar la interface que acabamos de definir. No nos complicaremos mucho, simplemente guardaremos los datos que recibimos en un fichero xml. Tendremos en cuenta que hemos renombrado los ficheros de Service1 a WcfPersonasService.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.Text;

using PersonasWCFService;

using System.IO;

using System.Xml.Serialization;

using System.Xml;

 

namespace WcfPersonasService

{

public class WcfPersonasService : IWcfPersonasService

{

public AddPersonaResult AddPersona(Persona persona)

{

try

{

string path =

String.Format("C:\\temp\\Persona{0}.xml", Guid.NewGuid());

using (FileStream fs = new FileStream(path, FileMode.CreateNew))

{

XmlSerializer serializador =

new XmlSerializer(persona.GetType());

serializador.Serialize(fs, persona);

fs.Close();

return new AddPersonaResult { ReturnCode = "OK" };

}

}

catch (Exception)

{

return new AddPersonaResult {

ReturnCode = "ERR",

Mensaje="Se ha producido un error" };

}

}

}

}

Como queremos publicar el servicio en un servidor web IIS, necesitamos el archivo WcfPersonasService.svc - que Visual Studio debe haber creado cuando hemos creado el proyecto de tipo "Web , servicio de WCF".

 

<%@ ServiceHost Language="C#"

Service="WcfPersonasService.WcfPersonasService"

CodeBehind="WcfPersonasService.svc.cs" %>

La configuracion siempre es un punto delicado en WCF , el archivo de configuracion no es más que in web.config clásico con la seccion system.serviceModel.

Lo primero recordar que es un EndPoint, se trata de un concepto básico e imprescindible en WCF. Un EndPoint es cada uno de los extremos que intervienen en una comunicacion. El EndPoint define tres elementos básicos de la comunicacion:

  • Adress - la direccion URI donde se expone el servicio.
  • Binding - el enlace que vamos a utilizar. Este parametro define el canal de la comunicacion.
  • Contract - la interface, es decir las operaciones que vamos a poder realizar.

Al conjunto de estas tres propiedades se las conoces como el "ABC" de WCF, en alusion a las iniciales de Adress, Binding y Contract. En realidad el EndPoint dispone de más parametros pero no dejan de ser especificaciones de estos tres.

Es importante destacar que PHP no es compatible con la version actual de SOAP por lo que nuestro binding debe ser forzosamente basicHttpBinding - que se correspondría con SOAP 1.1 - y no wsHttpBinding - SOAP 1.2-

Configuraremos nuestro servidor de la siguiente manera.

 

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="HttpBinding" />

</basicHttpBinding>

</bindings>

<services>

<service

behaviorConfiguration="WcfPersonasService.DefaultBehavior"

name="WcfPersonasService.WcfPersonasService">

<endpoint name="HttpPersonasService"

address="http://localhost:12730/WcfPersonasService.svc"

binding="basicHttpBinding"

contract="WcfPersonasService.IWcfPersonasService"

bindingConfiguration="HttpBinding" />

<endpoint name="mex"

address="mex"

binding="mexHttpBinding"

contract="IMetadataExchange" />

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior name="WcfPersonasService.DefaultBehavior">

<serviceMetadata httpGetEnabled="true" />

<serviceDebug includeExceptionDetailInFaults="false" />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

Existe un segundo EndPoint, el llamado "mex" que se encarga de proporcionar los metadatos y que añade WCF por defecto.

El cliente .NET

Ahora creamos una aplicacion de Windows forms para probar nuestro servicio. AgrEgamos un nuevo proyecto a la solucion de Visual Studio, de tipo formualrios de windows.

Ahora necesitamos agragar la referencia al servicio. Sobre el explorador de Soluciones, agregamos una referencia al servicio , que en nuestro caso está ubicado en http://localhost:12730/WcfPersonasService.svc.

Cuando añadimos la referencia, Visual Studio crea una clase "proxy" para trabajar con el servicio. Solo tenemos que instanciar esta clase - WcfPersonasServiceClient - e invocar al método AddPersona para ejecutar el servicio.

Si configuramos Visual Studio para ver los archivos ocultos podremos ver el código que se genera al añadir una referencia al servicio.

Ahora volvemos al formulario por defecto de la aplicacion - Form1 -, añadimos un boton y lo programamos con el siguiente código.

 

private void button1_Click(object sender, EventArgs e)

{

AddPersonaResult res = null;

using (WcfPersonasServiceClient client = new WcfPersonasServiceClient())

{

Persona persona = new Persona();

persona.Nombre = "Pedro";

persona.PrimerApellido = "Herrarte";

persona.SegundoApellido = "Sanchez";

 

persona.Documento =

new Documento { Tipo = "NIF",

Numero = "00000000",

Letra = "T" };

 

res = client.AddPersona(persona);

}

MessageBox.Show(res.ReturnCode);

}

El código es muy sencillo: instanciamos el proxy, asignamos las propiedades y ejecutamos el método AddPersona.

El cliente de .NET es otro extremo de la configuracion ... por lo tanto tenemos que configurar el EndPoint correspondiente. Esto se hace al agragar una nueva "Service Reference"

El archivo de configuracion:

 

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="HttpPersonasService"

closeTimeout="00:01:00"

openTimeout="00:01:00"

receiveTimeout="00:10:00"

sendTimeout="00:01:00"

allowCookies="false"

bypassProxyOnLocal="false"

hostNameComparisonMode="StrongWildcard"

maxBufferSize="65536"

maxBufferPoolSize="524288"

maxReceivedMessageSize="65536"

messageEncoding="Text"

textEncoding="utf-8"

transferMode="Buffered"

useDefaultWebProxy="true">

<readerQuotas maxDepth="32"

maxStringContentLength="8192"

maxArrayLength="16384"

maxBytesPerRead="4096"

maxNameTableCharCount="16384" />

<security mode="None">

<transport

clientCredentialType="None"

proxyCredentialType="None"

realm="" />

<message clientCredentialType="UserName"

algorithmSuite="Default" />

</security>

</binding>

</basicHttpBinding>

</bindings>

<client>

<endpoint

address="http://localhost:12730/WcfPersonasService.svc"

binding="basicHttpBinding"

contract="PersonasServiceReference.IWcfPersonasService"

bindingConfiguration="HttpPersonasService"

name="HttpPersonasService" />

</client>

</system.serviceModel>

Tener toda la configuracion está en el archivo externo completamente desacoplado del código. WCF.

El cliente PHP

Por fin el úlitmo eslabon de la cadena. El cliente de PHP.

Abrimos nuestro editor Aptana y creamos un nuevo proyecto de PHP. Antes de nada tendremos que tener en cuenta:

  • Solo vamos a poder consumir el servicio si este se expone a través de basicHttpBinding. PHP no es compatible con el estandar SOAP 1.2. 
  • Con la librería nuSOAP no he consguido invocar métodos con tipos complejos (clases) como parámetros.

Bien, el proceso no es complejo - cuando se sabe como!. Los pasos a seguir son:

  • Crear una instancia de la clase SoapClient.Necesita de la dirección de descripcion del servicio (WSDL)
  • Representar los tipos complejos como arrays.
  • Envolver todo en un nuevo array y llamar al método. Hay que tener en cuenta que el nombre de este array debe coincidir con el nombre del parámetro en el servicio - en caso contrario se recibirá un valor null en el servicio.

El código de la página es el siguiente:

 

<?php

$wsdl = "http://localhost:12730/WcfPersonasService.svc?wsdl";

$soapClient = new SoapClient($wsdl);

$documento = array('Tipo' => 'NIF',

'Numero' => '000000000001',

'Letra' => 'K');

$persona = array ('Nombre' => 'Pedro',

'PrimerApellido' => 'Herrarte',

'SegundoApellido' => 'PHP',

'Documento' => $documento);

 

$retval = $soapClient->AddPersona(array('persona' => $persona));

$code = $retval->AddPersonaResult->ReturnCode;

 

if ($code == "OK") {

echo "<h1>Proceso correcto</h1>";

}

else {

echo "<h1>Se ha producido error</h1>";

echo "<h2>" + $retval->AddPersonaResult->Message + "<h2>";

}

?>

Con esto estaremos consumiendo un servicio de WCF desde PHP. Objetivo cumplido.

Consideraciones sobre el rendimiento y conclusiones.

Me llama muchisimo la atención el hecho del escasisimo soporte que ofrece PHP para trabajar con web services, las lista de quejas es larga:

  • Soporte experimental en las clases nativas.
  • Compatibilidad reducida. Solo es compatible con SOAP 1.1
  • Trabajo basado en arrays, es decir: no tipado y susceptible a errores.

Pero donde de verdad PHP falla es en el rendimiento. Cada vez que neceistemos invocar al web service, es necesario llamar antes al wsdl. Esto quiere decir que cada vez que quiero ejecutar el método "AddPersona",PHP pide antes al servcio la clase Persona, la clase Documento,  ... y finalmente ejecuta el método. Esto reduce al mínimo el rendimiento y "mata" toda posibilidad de escalabilidad del sistema.

Vamos que no me hace ninguna gracia.

Saludos, DJK

 


 Versión para imprimir  Foros de consulta

 
muy bueno por Mihai Mosor
Respuesta recibida el [23/09/2009 08:58:24]
Eso es lo que estaba buscando, pero la verdad es que es un quebradero de cabeza. Sabía que PHP utiliza muy bien lo del DOM y XML pero no sabía que ofrece poca compatibilidad con con los servicios de .NET; Por cierto, ¿hay que configurar web.config a mano? brrrrrr, hay muchos parámetros que parecen imposibles de recordar. Espero que se auto-genere solo.
Muy bueno artículo, esto es un ahorro de consultar 1001 páginas+foros+libros.
Saludos();

 
Para configurar el config por devjoker
Respuesta recibida el [23/09/2009 09:20:30]
Para configurar el web.config existe una utilidad en Visual Studio llamada "WCF Service Configuration Editor", está en el menu Tools - o herramientas!. Pero me ha parecido mas didactico explicar el XML que no la herranienta. El secreto está en recordar el ABC.

Saludos,
DJK


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



 Versión para imprimir

Ejecutar un servicio WCF desde PHP
Autor: Pedro Herrarte Sánchez
Visitas: 1140 Fecha de publicación: 17/09/2009
Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación.

Posee mas de diez años de experiencia trabajando para las principales empresas de España.

Es especialista en tecnologías .NET, entornos Web, bases de datos (SQL Server y ORACLE) e integración de sistemas.

Es experto en desarrollo (C#, ASP.NET, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE).

Es fundador, diseñador y programador de www.devjoker.com.




Visitas: 90 | Comentarios: 2 | Archivo: Articulos
02/02/2010 iPad vs Telesketch
Visitas: 794 | Comentarios: 2 | Archivo: Articulos
Categorias: Humor
Visitas: 749 | Comentarios: 3 | Archivo: Articulos
Visitas: 3145 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 14504 | Comentarios: 7 | Archivo: Articulos
Categorias: C#|Seguridad
Visitas: 1478 | Comentarios: 3 | Archivo: Articulos
Visitas: 691 | Comentarios: 2 | Archivo: Articulos
Visitas: 369 | Comentarios: 0 | Archivo: Articulos
Visitas: 2013 | Comentarios: 2 | Archivo: Articulos
Categorias: C#

Útimos temas recibidos en los foros ...
certificado de pensiones del bbva horizonte por danger ... [Actualidad] 123 12/01/2010
certificado de pensiones horizonte por ruby ... [Actualidad] 32 14/02/2010
jalar datos a un listbox por happypeace31 ... [Visual Basic .NET] 1 21/09/2009
fecha valida datetimepicker por jess ... [Visual Basic .NET] 1 04/03/2010
Mi numero de autogenerado por chari ... [Visual Basic .NET] 4 01/03/2010
quiero saber en que entidad estoy afiliada a cesantias y pensiones por adriana ... [WIN 98/NT/2000/XP] 23 28/11/2009
Certificado de afiliacion Pensiones y Cesantias por VIVIANA ... [Actualidad] 1 10/03/2010
CERTIFICADO por LIZETH ... [Actualidad] 0 11/03/2010
certificado de afiliación de pensiones y cesantias por secre ... [Actualidad] 111 28/01/2010
Solicitud certificado de afiliaciones a pensiones y cesantias proteccion por hz ... [Actualidad] 54 10/02/2010
certificado pensiones horizonte por angela patricia rodriguez ... [Actualidad] 135 26/01/2010
pensiones por eduard ... [Visual Basic 6.0] 0 11/03/2010

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
03/10/2006 Programacion con C#    forma parte de...Tutorial C#
11/09/2006 Trabajar con datos de tipo BLOB en ORACLE
21/07/2006 Funciones integradas de PL/SQL    forma parte de...Tutorial PL/SQL
18/09/2008 Generar archivos PDF con C#
23/05/2006 Cursores en PL/SQL    forma parte de...Tutorial PL/SQL
22/10/2005 El lenguaje SQL    forma parte de...Tutorial SQL
01/01/2006 Consultas agregadas    forma parte de...Tutorial SQL
06/10/2009 Simular TRUNC en SQL Server
14/04/2009 Tutorial rápido de Entity Framework y Linq To Entities
09/10/2006 Variables y tipos de datos    forma parte de...Tutorial C#

 

Encuesta
¿A que perfil te adaptas mejor?




[Ver] [Votar]