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: 952 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.




02/02/2010 iPad vs Telesketch
Visitas: 274 | Comentarios: 0 | Archivo: Articulos
Categorias: Humor
Visitas: 175 | Comentarios: 2 | Archivo: Articulos
Visitas: 2581 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 13523 | Comentarios: 7 | Archivo: Articulos
Categorias: C#|Seguridad
Visitas: 1097 | Comentarios: 3 | Archivo: Articulos
Visitas: 575 | Comentarios: 2 | Archivo: Articulos
Visitas: 312 | Comentarios: 0 | Archivo: Articulos
Visitas: 1502 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 1073 | Comentarios: 0 | Archivo: Articulos

Útimos temas recibidos en los foros ...
WebControls en ASP .NET por Novato ... [ASP.NET] 88 06/05/2006
certuficado de afiliacion a porvenir por ede ... [Actualidad] 1 05/02/2010
certificado de afiliación de pensiones y cesantias por secre ... [Actualidad] 22 28/01/2010
como instalar visual basic 6.0 por sharon ... [WIN 98/NT/2000/XP] 8 21/04/2009
consulta en oracle por pariona ... [ORACLE] 0 08/02/2010
Es posible que me envien un certificado de pensiones por Nidia ... [Actualidad] 0 08/02/2010
necesito saber mi código de autogenerado ESSALUD por hermes ... [Visual Basic .NET] 17 01/10/2009
certificado de penciones horizonte por jhon freyder luna lopez ... [Actualidad] 1 05/02/2010
Solicitud de certificado por Proyelco ... [Actualidad] 0 08/02/2010
quiero saber en que entidad estoy afiliada a cesantias y pensiones por adriana ... [WIN 98/NT/2000/XP] 9 28/11/2009
certficado de pension por dannyjsb ... [Actualidad] 0 08/02/2010
Cual es el procedimiento para proteger Procedimientos almacenados y tablas por Mabe ... [SQL Server] 0 08/02/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 ...
05/07/2007 Consultar datos en Transact SQL    forma parte de...Tutorial de Transact SQL
24/07/2006 SQL Dinamico    forma parte de...Tutorial PL/SQL
22/10/2005 Componentes del lenguaje SQL    forma parte de...Tutorial SQL
27/08/2007 Enviar email con C#
23/05/2006 Cursores en PL/SQL    forma parte de...Tutorial PL/SQL
21/07/2006 Funciones integradas de PL/SQL    forma parte de...Tutorial PL/SQL
25/08/2007 Variables en Transact SQL    forma parte de...Tutorial de Transact SQL
26/07/2006 Secuencias    forma parte de...Tutorial PL/SQL
24/05/2007 Tipos de datos en Transact SQL    forma parte de...Tutorial de Transact SQL
12/01/2006 Introducción a PLSQL    forma parte de...Tutorial PL/SQL

 

Global SEO Partner

Our Global seo partner regarding international seo is located in spain and gives excellent service.

International expansion

The International expansion of our website is focused for North america, Europe and Latin America.

Brand tracking

Brand tracking is a way to make sure we control what is said about our brand online.

Encuesta
¿A que perfil te adaptas mejor?




[Ver] [Votar]