8.30.2009

Manejo de Excepciones en WPF

En una ocasión estando desarrollando un proyecto en WPF con varios desarrolladores más, surgió la pregunta ¿Cómo manejar las excepciones en WPF? Y es que esta pregunta puede parecer sencilla, ya que como todos sabemos en .NET existe el manejo de excepciones a través de la estructura try … catch … finally. Sin embargo, cuando se esta trabajando en el UI de un proyecto en WPF y varios desarrolladores hacen y modifican eventos y procedimientos en las pantallas – validación, llamadas a lógica de negocios y manejo de errores – es importante saber como va a reaccionar la aplicación a errores no esperados en secciones de código en donde no se han programado bloques de control de errores. En otras palabras lo que se busca es una forma central de manejar las excepciones, tal y como se logra hacer de manera sencilla en ASP.NET cuando en el archivo web.config le indicamos a la aplicación que en caso de un error no previsto y no atrapado, despliegue el error en una página específica. Durante esta experiencia investigué cuál era el modo más cercano de lograr este comportamiento en WPF y este post el resultado de esta investigación.

En primera instancia, si existe un lugar central desde donde crear un método que nos permita manejar los errores que se disparen en la aplicación WPF y que no hayan sido manejados por bloques de try…catch previamente. Este lugar es en el archivo App.xaml.cs – en el caso de C#. En esta clase podemos definir un manejador de eventos para el evento de aplicación DispatcherUnhandledException el cual se va a disparar cada vez que ocurre un evento inesperado. A continuación el código de la clase App.

using System.Windows.Threading;



/// <summary>
///
Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
string errorMessage = string.Format("Ocurrió una excepción inesperada. {0}{1}"
, Environment.NewLine, e.Exception);
MessageBox.Show(errorMessage, "Error atrapado en el obj Application");
e.Handled = true;
}
}


En este caso vamos a necesitar agregar el namespace using System.Windows.Threading que es el namespace donde se encuentra declarado el tipo DispatcherUnhandledExceptionEventArgs el cual es el que vamos a utilizar como parámetro para manejar el error. Esta variable – e en nuestro caso – contiene una referencia a la excepción que no ha sido manejada y una bandera indicando si la excepción ha sido manejada o no. Es importante destacar que este evento se va a disparar solamente en el thread del UI, otras excepciones lanzadas desde otro thread no van a ser atrapadas – lo veremos en el ejemplo. En el archivo App.xaml, vamos a agregar el evento y su correspondiente manejador, el cual en nuestro caso es App_DispatcherUnhandledException.



image Seguidamente procedemos a agregar el código correspondiente en WPF y XAML. Primeramente vamos a agregar 3 botones, el primero de ellos no va a manejar la excepción y por lo tanto debe de ser atrapada en el manejador global de errores, el segundo de ellos atrapa la excepción localmente ya que tiene un bloque try … catch y el último lanza una excepción en otro thread, por lo tanto no es manejada en nuestro evento de manejo de errores global a la aplicación. El código en cs es el siguiente.



private void btnGuardar_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}

private void button1_Click(object sender, RoutedEventArgs e)
{
try
{
throw new NotImplementedException();
}
catch (NotImplementedException ex)
{

MessageBox.Show(ex.Message, "Error manejado en la ventana");
}
}

private void button2_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
throw new NotImplementedException();
};
worker.RunWorkerAsync();
}



Del lado de XAML, agregamos los 3 botones que van a disparar los eventos anteriores.



image La pantalla en modo gráfico luce así:



image Al ejecutar el primer botón – el error se maneja en el App.xaml.cs - el resultado es el siguiente:



image Al utilizar el botón en donde se maneja el error localmente el resultado es el siguiente:



image





Por último, al lanzar una excepción en otro thread no se dispara ningún error y este no se maneja de forma global.



image



De esta manera podemos manejar de manera unificada las excepciones sin manejar en aplicaciones WPF.







Technorati Tags: ,,

8.25.2009

Manejo del Scope con Unity

Cuando se trabaja con IoC containers existe un factor que en muchas ocasiones se ignora a la hora de crear instancias dinámicamente: el scope del objeto que estamos creando. En este post vamos a analizar las opciones para el manejo del scope cuando utilizamos el Unity Application Block.

¿Qué es el Scope?

El scope – alcance – de un objeto es la cantidad de tiempo o las llamadas a los métodos en los cuales un objeto existe. Es decir, el scope es el contexto bajo el cual un identificador se refiere a la misma instancia. También podemos definir el scope como la cantidad de tiempo que el estado de un objeto persiste. Cuando el contexto del scope finaliza, cualquier objeto ligado a este scope queda fuera de alcance y no pueden inyectarse de nuevo en otras instancias.

El Scope y los IoC

La verdadera ventaja del scope en los IoC es que permite modelar el estado de los objetos de forma declarativa. Esto se logra diciendole al inyector que una llave en particular esta ligada a un scope, y por lo tanto se puede manipular la construcción y el lige entre objetos en el contexto del inyector.

El aplicar correctamente el manejo del scope significa que un código trabajando en un contexto particular no esta conciente del contexto en que se ejecuta. Es responsabilidad del inyector el administrar estos contextos. Esto significa que se tiene una separación entre la aplicación y la infraestructura, sino que también estos servicios pueden ser utilizado para muchos propósitos alternando simplemente el scope seleccionado. Para visualizar mejor esto vamos a trabajar con un ejemplo.

deptartment.Print("drojas", "Project Plan", injector.Resolve<Printer>());
deptartment.Print("jcalvo", "work items", injector.Resolve<Printer>());
deptartment.Print("palfaro", "todo's", injector.Resolve<Printer>());


Supongamos que en un departamento de una empresa trabajan 3 usuarios, y cada uno tiene un documento que mandar a imprimir. Basándonos en el ejemplo anterior podríamos decir que la impresora la utiliza primero drojas, seguidamente jcalvo y por último palfaro. Si la impresora es de poca capacidad y los documentos de drojas y jcalvo son muy grandes, puede ser que palfaro se quede sin tinta o sin hojas para imprimir.



image



En este caso el injector distribuye la tinta a través de la misma impresora – misma instancia - entre todos los que van imprimiendo. Este es un ejemplo del contexto: Todos los trabajadores del departamento comparten la misma área, y por lo tanto comparten la impresora. En este caso la impresora esta accesible a través de un scope del tipo singleton.





Otro ejemplo de contexto sería cuando cada uno de los trabajadores del departamento tienen su propia impresora. Teoricamente, si utilizamos el ejemplo anterior, podríamos decir que cada trabajador imprime en su impresora; y digo teoricamente porque esto no es absolutamente cierto, ya que si palafaro manda a imprimir dos veces el mismo documento, estaríamos utilizando dos impresoras diferentes:



deptartment.Print("drojas", "Project Plan", injector.Resolve<Printer>());



deptartment.Print("jcalvo", "work items", injector.Resolve<Printer>());



deptartment.Print("palfaro", "todo's", injector.Resolve<Printer>());



deptartment.Print("palfaro", "todo's", injector.Resolve<Printer>());



En este caso, estamos trabajando sin alcance, y lo que estamos diciendole al injector es que debe de crear una nueva instancia por llamado.



Controlando el Scope con Unity


El scope en Unity se puede controlar vía configuración o vía código. El contenedor de Unity administra la creación y la resolución de objetos basado en el scope que se especifica cuando se registra el tipo o de lo contrario se utiliza el scope por defecto – sin scope.



Cuando se registra un tipo utilizando el metodo RegisterType,  el comportamiento por defecto es crear una nueva instancia del tipo solicitado cada vez que se invoca el metodo Resolve o ResolveAll. El contenedor no mantiene guarda una referencia al objeto. Sin embargo, cuando se desea un comportamiento Singleton para los objetos que se van a instanciar, el contenedor mantiene una referencia a los objetos creados.



Cuando se registra un objeto existente utilizando el método RegisterInstance el comportamiento por defecto es que el contenedor tome la administración del tiempo de vida del objeto que se pasa como parámetro al objeto. Esto significa que el objeto se mantiene en el scope mientras el contenedor este en el scope; una vez que el contenedor salga del scope o cuando se elimina la instancia del contenedor explícitamente, el objeto registrado será inalcanzable.



Unity utiliza lo que se conoce como “lifetime managers” para controlar como se guardan las referencias a las instancias de los objetos y como el contenedor elimina estas instancias. Unity incluye 3 “lifetime managers” que pueden ser utilizados directamente en el código.





  1. ContainerControlledLifetimeManager: Unity retorna la misma instancia del tipo registrado cada vez que se llama al metodo Resolve, ResolveAll o cuando el mecanismo de dependencia inyecta instancias en otras clases. Este es el mecanismo para implementar un comportamiento Singleton. Este lifetime manager se utiliza por defecto para el metodo RegisterInstance si no se especifica algún otro. Si se desea un comportamiento singleton que se crea cuando se utiliza el método RegisterType, se debe de especificar de forma explícita.




  2. ExternallyControlledLifetimeManager: Este manager permite registrar tipos y objetos existentes en el contenedorm, pero mantiene una referencia “débil” a los objetos que se crean utilizando Resolve y ResolveAll. Unity retorna la misma instancia cuando se utilizan estos métodos, pero el contenedor no mantiene una referencia fuerte a los mismos luego de crearlos, por lo que el Garbage Collector puede eliminar los objetos si no existe código que mantenga una referencia fuerte a los objetos creados.




  3. PerThreadLifetimeManager: Unity retorna la misma instancia por thread del tipo registrado cada vez que se invoca el método Resolve o ResolveAll. Este lifetime manager implementan un singleton por thread, por lo tanto retorna diferentes objetos para cada thread.





    1. Si se utiliza el método RegisterType, Unity crea una nueva instancia la primera vez que se resuelve el tipo en un thread específico utilizando Resolve o ResolveAll. Las siguientes invocaciones retornan la misma instancia en el thread.




    2. Si se utiliza el método RegisterInstance, se obtiene el mismo comportamiento que ofrece el método RegisterType. Por esta razón no se recomienda utilizar el método RegisterInstance para registrar un objeto utilizando este lifetime manager.





A continuación vamos a ver el uso de estos lifetime managers. Inicialmente vamos a crear una interface que se llamará IPrinter la cual tiene un método para imprimir y una propiedad llamada Name donde vamos a almacenar el código hash de la instancia utilizada, esto nos permitira ver si la instancia es un singleton o no.



public interface IPrinter
{
string Name { get; set; }
string Print(string document);
}


Seguidamente vamos a crear dos clases que implementan esta interface: LaserPrinter e InkPrinter. Estas clases son las que vamos a registrar e instanciar utilizando Unity y sus lifetime managers.



public class LaserPrinter : IPrinter
{
public string Name { get; set; }
public LaserPrinter()
{
Name = this.GetHashCode().ToString();
}
public string Print(string document)
{
return "Imprimiendo el documento: " + document + " en laser";
}
}

public class InkPrinter : IPrinter
{
public string Name { get; set; }
public InkPrinter()
{
Name = this.GetHashCode().ToString();
}
public string Print(string document)
{
return "Imprimiendo el documento" + document + " en Tinta";
}
}



Seguidamente creamos en el método main, el código necesario para registrar y crear las instancias utilizando el contenedor de Unity.



static void Main(string[] args)
{
using (IUnityContainer unityContainer = new UnityContainer())
{
//La impresora laser la vamos a registrar como un singleton
unityContainer.RegisterType<IPrinter, LaserPrinter>("Laser", new ContainerControlledLifetimeManager());
//La impresora de tinta le vamos a dar un tiempo de vida pasajero, es decir, vamos a crear
//una instancia por llamado.
unityContainer.RegisterType<IPrinter, InkPrinter>("Ink");

//Impresora con hash propio
IPrinter printer = unityContainer.Resolve<IPrinter>("Ink");
Console.WriteLine(printer.Print("Tareas"));
//Impresora con singleton
IPrinter printer2 = unityContainer.Resolve<IPrinter>("Laser");
Console.WriteLine(printer2.Print("Errores"));
//Impresora con singleton
IPrinter printer3 = unityContainer.Resolve<IPrinter>("Laser");
//Impresora con hash propio
IPrinter printer4 = unityContainer.Resolve<IPrinter>("Ink");

Console.WriteLine(printer.Name);
Console.WriteLine(printer2.Name);
Console.WriteLine(printer3.Name);
Console.WriteLine(printer4.Name);
}
}



El resultado al ejecutar el código anterior es el siguiente:



image 



La pregunta que nos surge ahora es: ¿cuándo usar un singleton o cuando usar un alcance pasajero? Pues desde mi punto de vista, un buen lugar para utilizar un singleton es una capa de acceso a datos, ya que por lo general estas operaciones son unitarias y especificas – leer datos, escribir un dato – y no necesitamos realmente crear una nueva instancia para poder tener acceso a estos componentes. Igualmente, operaciones en donde las operaciones para inicializar un objeto son muy “pesadas” y en donde estas configuraciones de arranque son solo de lectura, son buenos candidatos para un singleton.



Technorati Tags: ,,,

8.15.2009

¿Por qué es importante el MSE – Managed Service Engine?

En muchas ocasiones cuando estoy en consultorias relacionadas con arquitecturas orientadas a servicios – SOA – tengo que hacer mucho enfasis en el hecho de que tener web services en la organización no significa que tengo una arquitectura orientada a servicios. Al mismo tiempo, se me consulta que papel juega el MSE en la transición hacia una arquitectura orientada a servicios. En este post voy a tratar de aclarar estas dos dudas.

Tener Servicios Web no es tener SOA

Existe la creencia errada respecto a que tener servicios web para ser consumidos tanto internamente como externamente, me da automáticamente una arquitectura orientada a servicios. En realidad cuando implementamos servicios web dentro de nuestra organización estamos creando una arquitectura que se conoce como punto a punto. Esto se puede notar si tenemos muchos servidores Web hospedando los servicios, y/o si tenemos que consumir servicios web de muchas otras organizaciones ya sean externas o internas. En la siguiente figura podemos ver esta arquitectura.

image

En la figura anterior, podemos ver que las aplicaciones hacen referencias directas a servicios que retornan funcionalidad de negocios de las aplicaciones que desean acceder, teniendo en sus referencias el servidor donde estan hospedados estos servicios, el uri del servicio y el contrato de la implementación del servicio. Esto nos pone en desventaja ya que si tenemos que mover algún servicio de servidor, tenemos que actualizar todos los consumidores del mismo, ya que hay una referencia directa al servicio a través del servidor. Peor aún, si estamos consumiendo servicios externos y nos cambian la dirección del servicio, nuestra aplicación no funcionará correctamente si no se nos notifica a tiempo.

Otro problema que tendríamos además del ruteo de los mensajes es el manejo de los errores. Al tener diversas fuentes de donde consumir los servicios, los errores se van a almacenar y administrar en cada uno de los servidores internos o externos, de forma tal que no podemos crear logs centralizados para identificar que sucede en caso de presentarse algún error.

Además, dentro de los patrones de una arquitectura orientada a servicios, el concepto de servicio web no es exclusivo para su implementación. Esto por que en realidad en una arquitectura orientada a servicios yo puedo integrarme con servicios que implementen protocolos diversos tales como HTTP(s), TCP, etc.

Como me ayuda el MSE a tener una Arquitectura Orientada a Servicios

Una de las razones principales por la cual las organizaciones adoptan una arquitectura orientada a servicios es por la promesa de una alta flexibilidad en las aplicaciones. Esta promesa viene del hecho de que una arquitectura SOA diseñada correctamente reduce el tiempo de construcción de las aplicaciones y de los nuevos requerimientos en las aplicaciones ya existentes.

El primer requerimiento de una aplicación SOA bien diseñada es que cualquier aplicación puede ser accesada vía servicios ya sea interna o externamente lo cual permitirá la reutilización.  Esto nos va a permitir desarrollar nuevas aplicaciones que requieran funcionalidad de las aplicaciones ya implementadas de forma más rápida y sencilla porque vamos a requerir menos código para tener acceso a la funcionalidad deseada. Sin embargo, si debo escribir cada servicio desde cero este requerimiento no se puede cumplir o cumplirlo sería muy costos en tiempo e inversión. Si se construyen estos servicios como aplicaciones aisladas, se van a crear servicios con funcionalidades duplicadas, será dificil tener un inventario de servicios disponibles y sus funcionaldiades, los logs de errores de los servicios estarían en cada uno de los servidores que almacenan el servicio, por citar alguno de los inconvenientes que tendríamos si no utilizamos una arquitectura orientada a servicios.

El segundo punto a tratar es que una arquitectura SOA bien diseñada tiene que tomar en cuenta es el cambio constante. En un ambiente empresarial SOA, los servicios tienden a cambiar mientras evolucionan. Estos cambios son de dos tipos: cambios en la interface y cambios en la implementación. El reto esta en encontrar una manera de convivir con la evolución de los servicios y el minimizar el efecto del cambio en los servicios en el consumidor de los mismos.

La pregunta que nos surge ahora es: ¿Qué rol juega el MSE en este escenario? Pues bien, el MSE nos permite llevar a cabo virtualización de servicios. La virtualización de servicios es un esquema de instalación y administración de servicios que nos brinda toda la “plomería” requerida por todos los servicios dentro de la organización. Esto le permite al desarrollador enfocarse en construir nueva funcionalidad y nos brinda una base de funcionalidad donde se requiere conectar con nueva funcionalidad.

Respecto al manejo de los cambios en los servicios, el MSE nos permite manejar este problema a nivel de operación. Este nos da la posibilidad de crear nuevas versiones de las operaciones existentes de los servicios. El MSE nos brinda esta funcionalidad por que el mantiene la interface de la operaciones del servicio conectada pero separada de su implementación, siendo este el principio básico para la virtualización de servicios. A través de la virtualización de servicios se pueden tener tantas versiones de la operación del servicio activas como sea necesarias, pero solamente una puede ser publicada a través del WSDL. Esta característica nos permite soportar la compatiblidad hacia versoines anteriores ya que los usuarios con versiones anteriores pueden serguir consumiendo el servicio y los nuevos usuarios usan el WSDL publicado del nuevo servicio, ambos casos sin complicación alguna. En el momento en que todos los clientes se muevan a la última versión del servicio, las versiones anteriores pueden ser desactivadas. La siguiente figura nos muestra la arquitectura del funcionamiento del MSE y sus funcionalidades en cada uno de los componentes que lo conforman.

image

Technorati Tags: ,,,

8.04.2009

Entendiendo el MSE – Managed Service Engine

Como comenté en un post anterior, el MSE es una herramienta open source que me permite obtener funcionalidad para poder administrar y llevar a cabo una transición entre una arquitectura punto a punto – o servicios web instalados en diversos servidores y web – a una arquitectura orientada a servicios ( SOA ). En este post ahondaré un poco más en los componentes del MSE.

El MSE esta formado de tres componentes principales: el service runtime engine, el catalogo de servicios, y la herramienta de administración para implementar la virtualización de los servicios. El service runtime engine esta implementado como un servicio de windows que administra un conjunto de instancias de hosting de servicios WCF que se configuran automáticamente de la información que se encuentra en el catalogo de servicios.

El MSE esta compuesto de tres componentes internos lógicos: el messenger, el broker y el dispatcher. El messenger es el responsable de la normalización de los mensajes. El broker recibe los mensajes normalizados y es el responsable de seleccionar la versión específica de la operación. El dispatcher es el responsable de la invocación del servicio real que se desea consumir. La comunicación entre estos componentes sucede a través de canales WCF, esto permite distribuirlos en varios servidores y acomodarlos a diferentes infraestructuras que se puedan requerir.

El catalogo de servicios – también conocido como el repositorio de metadatos – contiene los modelos que guían los servicios virtuales contenidos en el runtime del MSE. Lo servicios se importan utilizando la herramienta de administración. Luego de importar el metadata del servicio, se definen los servicios virtuales para el consumo de los clientes.

Cuando se define un servicio virtual, se inicia escojiendo y configurando un binding de WCF. Se puede seleccionar que protocolo utilizar, que características de seguridad habilitar, o cualquier otra característica que soporte el binding seleccionado. También se puede especificar otros comportamietnos para los servicios como inspección de mensajes, transformación, información de versión, y cuales políticas se deben aplicar obligatoriamente utilizando la misma técnica.

El repositorio de metadata esta implementado como una base de datos SQL Server tradicional. Los consumidores no interactúan directamente con la base de datos aunque los datos se pueden publicar con el propósito de ser descubiertos. El MSE mantiene una distinción entre la noción de repositorio y el registro público. El repositorio es donde se encuentran los datos que guían el runtime, y el registro es un almacén separado de metadata de los sevicios que se puede hacer disponible para descubrir y consumir desde afuera.

La siguiente figura nos muestra un diagrama general con la ubicación de algunas de las funcionalidades que están disponibles en el MSE.

image

Technorati Tags: ,,