10.21.2010

Imágenes y WCF – Como Retornar una Imagen desde un Servicio en WCF y Presentarlo en WPF

Una de las tareas más normales en la vida de un desarrollador de aplicaciones es interactuar con imagenes. Esta tarea está normalmente relacionada con presentar imagenes que representan alguna información adicional respecto al dato o registro con el que estamos interactuando. Esto representa un desafío si nos apegamos a la arquitectura n-layer con una capa de servicios descrita en post anteriores. En este post vamos a trabajar en crear un servicio que retorna una imagen para que esta pueda ser utilizada por cualquier cliente.

WCF Message Encoders – Definición

En WCF utilizamos los endpoints para decirle a los clientes como es que se va a transferir los datos entre el cliente y el servidor. En el binding es donde se especifica como vamos a codificar nuestros mensaje para que el cliente pueda consumirlo. El atributo que establece como se codifican nuestros mensajes de respuesta en el binding es el messageEncoding. Desde el punto de vista de WCF el encoder seleccionado serializa el mensaje de salida y lo pasa a la capa de transporte. En la llegada – en el cliente – el encoder seleccionado recibe el mensaje y los deserializa utilizando el formato establecido. Para aclarar el concepto de Encoding/Decoding vamos a hacer una breve definción de los mismos. Encoding es el proceso de transformar un mensaje en una secuencia de bytes. Decoding es el proceso inverso.

WCF incluye 3 tipos de encoders para mensajes SOAP: Texto, Binario y MTOM – Message Transmission Optimization Mechanism. Estos encoders se representan a través de los siguientes elementos en el binding del mensaje:

  1. TextMessageEncodingBindingElement: soporta XML y SOAP. Es interoperable con clientes que no son WCF.
  2. BinaryMessageEncodingBindingElement: encoder de mensajes binario. No es interoperable.
  3. MTOMMessageEncodingBindingElements: MTOM es una tecnología para transmitir datos binarios en los mensajes WCF. Crea un balance entre eficiencia e interoperabilidad.

Ejemplo

Ahora vamos a trabajar directamente en WCF para obtener una imagen desde un directorio en la máquina que corre el servicio. Este servicio va a ser consumido por un cliente en WPF. Para este ejemplo voy a usar Web Developer Express 2010. Primero vamos a crear un proyecto del tipo  WCF Service Application. Si usas VS 2008, el tipo del proyecto debería ser a WCF Service Library.

image

Seguidamente procedemos a crear el contrato del servicio. En este caso solo vamos a tener una operación: GetUserImage. Esta operación recibo la ruta y el nombre de la fotografía que se desea obtener, y retorna un arreglo de bytes en donde la foto va codificada.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace ImageManagerService
{
[ServiceContract]
public interface IImageManager
{
[OperationContract]
byte[] GetUserImage(string pPath);
}

}


El siguiente paso es implementar este contrato. En este caso simplemente vamos a leer la imagen desde la ruta que se especifica en el parámetro y la vamos a retornar como un arreglo de bytes.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using System.IO;

namespace ImageManagerService
{
public class ImageManager : IImageManager
{
public byte[] GetUserImage(string pPath)
{
return File.ReadAllBytes(@pPath);
}
}
}


Seguidamente procedemos a trabajar con la configuración del servicio. En este caso recordemos que vamos a retornar una imagen y vamos a utilizar el decoder MTOM para transmitir nuestra imagen de una forma más rápida. Para esto tenemos que crear un nuevo binding configuration y proceder a ligarlo al servicio que queremos exponer a través de wsHttp.



<system.serviceModel>
<
bindings>
<
wsHttpBinding>
<
binding name="wsMTOM" maxReceivedMessageSize="665536" messageEncoding="Mtom"
/>
</
wsHttpBinding
>
</
bindings>
<
services>
<
service behaviorConfiguration="MTOMBehavior" name="ImageManagerService.ImageManager" >
<
endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsMTOM" contract="ImageManagerService.IImageManager"
/>
<
endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</
service>
</
services>
<
behaviors>
<
serviceBehaviors>
<
behavior name="MTOMBehavior">
<
serviceMetadata httpGetEnabled="true"/>
<
serviceDebug includeExceptionDetailInFaults="false"/>
</
behavior>
</
serviceBehaviors>
</
behaviors>


Lo importante a destacar en la configuración anterior, es que el binding del servicio esta configurado para codificar el mensaje utilizando MTOM, y por lo tanto optimizando la forma en que vamos a retornar la imagen – el arreglo de bytes – al cliente.



Ahora procedemos a crear el cliente de la aplicación. Para esta tarea vamos a utilizar el Visual C# express 2010, el cual nos va a permitir construir nuestra aplicación en WPF. Inicialmente vamos a crear una pantalla que me permite digitar la ruta y el nombre de la fotografía que queremos desplegar. La pantalla inicialmente luce así:



image



El siguiente paso es crear la referencia al servicio que tenemos expuesto.



image



Seguidamente procedemos a crear el código del evento Click del botón cargar para presentar la imagen en la pantalla.



private void btnCargar_Click(object sender, RoutedEventArgs e)
{
SRManageImage.ImageManagerClient cliente = new SRManageImage.ImageManagerClient();
byte[] imageBytes = cliente.GetUserImage(@txtImageName.Text);

BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = new MemoryStream(imageBytes);
image.EndInit();
imgPerson.Source = image;
}


El siguiente paso es ejecutar la aplicación. El resultado de esta ejecución se puede ver en la siguiente figura:



image



Technorati Tags: ,,

3 comentarios:

Wagner dijo...

Y si lo que se necesita es retornar una imagen de internet, por ejemplo del servicio de google static maps como se deberia hacer???;
Por ejemplo esta imagen:
http://maps.google.com/maps/api/staticmap?mobile=true&size=360x255&maptype=roadmap&sensor=false&markers=icon:http://bit.ly/ifQgqf|-0.281798,-78.534363

Gracias
Wagner Vásquez

Juan Manuel Lombana dijo...

Wagner esto no lo deberias montar en un servicio wcf si no en un handler ASHX en donde recuperas el recurso de la dirección; con el servicio se haría una doble petición.

Unknown dijo...

excelente amigo..linda experiencia gracias por tu aportacion..