Primero a
nuestra solución añadimos un nuevo proyecto tipo consola (yo lo nombré como
ProductoCliente), seguidamente añadimos la referencia a System.ServiceModel
esto en la pestaña .Net.
Ahora
necesitamos añadir la referencia a nuestro proyecto Web que aloja el servicio
WCF, esto para crear un proxy por medio del cual establecer la comunicación con
el servicio. Procedemos de la siguiente manera: sobre el proyecto recién creado
hacemos clic derecho y elegimos “Add Service Reference…” nos aparecerá una
pantalla como esta:
En esta
hacemos clic sobre el botón Discover, esto realiza una búsqueda de servicios en
nuestra solución. Elegimos el servicio asegurándonos que nuestro método exista
en la sección “Operations” y hacemos clic en OK:
Importante notar
que se cambió el namespace para hacerlo más descriptivo. Con esto hemos creado
el proxy necesario para comunicarnos con el servicio, pero ¿Dónde esta este
Proxy? Lo podemos encontrar haciendo clic el botón de mostrar todos los
archivos y luego expandiendo los folder: Service Reference, TestWCF, Reference.svmap
y haciendo doble clic sobre el archivo Refence.cs
Este proxy
fue creado automáticamente por Visual Studio, por lo que no es recomendable
modificarlo manualmente ya que los cambios se perderán cada vez que se
actualice la referencia.
Ahora
podemos dedicarnos a escribir el código de la aplicación cliente que consumirá
nuestro servicio WCF. El archivo Program.cs quedaría similar a esto:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using ProductoCliente.TestWCF; namespace ProductoCliente { class Program { static void Main(string[] args) { // Se crea el proxy para conectar con el servicio ProductoServicioClient proxy = new ProductoServicioClient(); // Probamos el metodo que obtiene los id de productos Console.WriteLine("Listado de Id de Productos"); string[] ListaProductos = proxy.ListaProductos(); foreach (string idProdcto in ListaProductos) { Console.WriteLine("Id Producto: {0}", idProdcto); } Console.WriteLine(); // Desconectado del servicio proxy.Close(); Console.WriteLine("Presione ENTER para terminar."); Console.ReadLine(); } } }
El código es fácil de entender, lo único relevante
de señalar es la desconexión del proxy; es importante realizar esta tarea para
liberar cualquier recurso abierto en el servidor donde esta alojado el servicio
WCF. Esta tarea también se puede lograr usando la sentencia using (ProductoServicioClient proxy = new
ProductoServicioClient()) {…} ya que la clase del servicio implementa la
interfaz IDisposable, lo que significa que al cerrar el bloque using se llamará
automáticamente al método close del proxy.
Si
ejecutamos esta consola obtendremos los id de los productos registrados en la
base de datos.
Pero aquí es
donde debemos detenernos y hacernos preguntas ¿Cómo la aplicación cliente sabe
donde encontrar el servicio? ¿Cómo maneja los tipos del mensaje de respuesta del
servicio? Esto es importante porque estas cuestiones son la esencia detrás del
WCF.
Revisemos
el App.config de nuestra aplicación cliente:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IProductoServicio" 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:50533/WCFServiceTest/Service.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IProductoServicio" contract="TestWCF.IProductoServicio" name="BasicHttpBinding_IProductoServicio" /> </client> </system.serviceModel> </configuration>
Todo esto
se creó cuando añadimos la referencia al servicio. En este momento nos interesa
la sección <client> es aquí donde se definen los endpoints, estos
proveen los detalles por medio de los cuales se vuelve posible la comunicación con
el servicio. Estos detalles son:
- - Address:
es la ruta donde el servicio esta localizado, en este ejemplo como el servicio
se encuentra hosteado en el servidor de desarrollo de Visual Studio la ruta es
una local via http y con un puerto generado por el mismo servidor.
- - Binding
y bindingConfiguration: especifica cosas como el mecanismo de trasporte, el
protocolo de comunicación, entre otros. Existen bindings preestablecidos dentro
del WCF, si no se especifica ninguno se utiliza el de por defecto, que es
basicHTTPBinding, el cual es compatible con la mayoría de Servicios Web
existentes. Ademas se pueden especificar cosas como Timeouts, encodings para los
mensajes y requerimientos de seguridad. Es muy importante señalar que la aplicación
cliente debe usar la misma información de binding que el servicio para que la comunicación
sea exitosa. Si se cambia el binding en el servicio debe replicarse ese cambio
en todas las aplicaciones cliente que lo consuman.
- - Contract:
es el que define los mensajes de envío y recepción para el servicio, este está especificado como una interfaz en el proxy que se crea al añadir la referencia
al servicio
Adicionalmente,
por medio del atributo name se puede definir un nombre para el endpoint, el
cual se puede usar en código para señalar que endpoint usar por medio de una
sobre carga en el constructor del proxy.
Ahora y finalmente, si recordamos la implementación de nuestro método ListaProductos en el servicio, recordaremos que el mensaje de vuelta se implementó como una lista de strings; sin embargo en nuestra aplicación cliente lo estamos recibiendo como un arreglo de strings ¿A que se debe esto?
Se debe a la manera en que se trasmiten los mensajes. Recordemos que estos se trasmiten por medio de XML. Esto es, cuando definimos operaciones en el servicio lo hacemos usando tipos del .Net framework, cuando se recibe un mensaje el WCF runtime convierte el XML entrante en tipos .Net y cuando envía la respuesta convierte tipos .Net en el XML de respuesta. Algo idéntico ocurre en la aplicación cliente. La mayoría de las veces el mapeo entre XML y tipos .Net es satisfactorio. Sin embargo para las colecciones XML hay varias representaciones válidas en tipos .Net y por defecto se utilizan arreglos para mapearlas.
Esto se
puede cambiar de la siguiente manera: hacemos clic derecho sobre la referencia del
servicio, en el menú emergente elegimos “Configure Service Reference…” nos
aparecerá una pantalla como la siguiente:
En el combo “Collection Type” elegimos System.Collections.Generic.List y hacemos
clic en OK. Ya con este cambio nuestra aplicación cliente ya no se ejecuta,
puesto que nos da un error de conversión de tipos entre el arreglo y la lista genérica.
Hacemos un ajuste de manera que cambiamos el array por:
Ejecutamos nuevamente y obtenemos el mismo resultado, sólo que ahora obtenemos una lista genérica con los id de los productos en lugar de un arreglo con los mismos.
En el siguiente post vamos a agregar más operaciones a nuestro servicio…
List<string> ListaProductos = proxy.ListaProductos();
Ejecutamos nuevamente y obtenemos el mismo resultado, sólo que ahora obtenemos una lista genérica con los id de los productos en lugar de un arreglo con los mismos.
En el siguiente post vamos a agregar más operaciones a nuestro servicio…
0 comments:
Publicar un comentario