11.29.2010

Utilizando Unity para Resolver un Problema de Negocio - 3

Siguiendo con el uso de Unity para trabajar problemas de negocios de una forma menos dependiente entre los componentes que desarrollamos, vamos ahora a tratar el caso en donde la clase recién instanciada tiene una referencia a otra clase que a su vez debe ser resuelta por el contenedor de IoC.

Supongamos que cada usuario tiene una relación de agregación con la interface IEmpresa y que dependiendo de la empresa se paga un cargo diferente cuando se realiza alguna transacción. La interface IEmpresa tendrá un método que solamente le aplica el cargo a la transacción. La relación de clases en el problema actual es la siguiente:

image

En nuestro código la implementación de nuestras clases lucirá así:

Interface IEmpresa

namespace Core.LogicaDeNegocios
{
public interface IEmpresa
{
void AplicarCargos();
}
}



Clase Oficina: Implementa IEmpresa



using System.Diagnostics;

namespace Core.LogicaDeNegocios
{
public class Oficina: IEmpresa
{
public void AplicarCargos()
{
Trace.WriteLine("Aplicar Cargos Oficina");
}
}
}


Clase EmpresaExterna: Implementa IEmpresa



using System.Diagnostics;

namespace Core.LogicaDeNegocios
{
public class EmpresaExterna: IEmpresa
{
public void AplicarCargos()
{
Trace.WriteLine("Aplicar Cargos Empresa Externa");
}
}
}



En la interface IUsuario agregamos la relación de agregación antes representada:



public interface IUsuario
{
IEmpresa Empresa { get; set; }

IUsuario Autenticar();
void Autorizar(object _form);
}



Ahora modificamos la clase Usuario, para que tenga una implementación de IEmpresa. Nótese que la clase debe implementar la propiedad expuesta en la interface y no necesariamente el mismo tipo en el atributo, ya que con solo tener una clase que implemente la interface, ya podemos crear la asociación.



public class Usuario : IUsuario
{
Oficina _oficina;

public Usuario(string pNombreUsuario, string pPassword)
{
Trace.WriteLine(string.Format("Datos del usuario. NombreUsuario: {0}, Password: {1}", pNombreUsuario, pPassword));
}

public IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autenticar Usuario");
}

public IEmpresa Empresa
{
get
{
return _oficina;
}
set
{
_oficina = value as Oficina;
}
}

}



Lo mismo ocurrirá con la clase Usuario_Web, con la diferencia que en Usuario_Web si vamos a crear un atributo del tipo IEmpresa.



public class Usuario_Web: IUsuario
{
IEmpresa _empresa;

public Usuario_Web(string pNombreUsuario, string pPassword)
{
Trace.WriteLine(string.Format("Datos del usuario. NombreUsuario: {0}, Password: {1}", pNombreUsuario, pPassword));
}

public virtual IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario Web");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autorizar Usuario Web");
}

public IEmpresa Empresa
{
get
{
return _empresa;
}
set
{
_empresa = value;
}
}
}


Por otro lado, vamos a crear una clase que hereda de Usuario_Web y que implementa su propia implementación de IEmpresa.



public class OtroUsuario : Usuario_Web
{
IEmpresa _empresa;

public OtroUsuario(string pNombreUsuario, string pPassword)
:base(pNombreUsuario, pPassword)
{
Trace.WriteLine(string.Format("Datos del usuario. NombreUsuario: {0}, Password: {1}", pNombreUsuario, pPassword));
}

public override IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Otro Usuario Web");
return this;
}

public IEmpresa Empresa
{
get
{
return _empresa;
}
set
{
_empresa = value;
}
}

}



Por último agregamos el nuevo mapping para tenerlo entre la lista de clases que pueden ser resueltas.



  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<
alias alias="IUsuario" type="Core.LogicaDeNegocios.IUsuario, Core.LogicaDeNegocios" />
<
namespace name="Core.LogicaDeNegocios" />
<
assembly name="Core.LogicaDeNegocios" />
<
container>
<
register type="IUsuario" name="usuario" mapTo="Usuario" />
<
register type="IUsuario" name="usuarioWeb" mapTo="Usuario_Web" />
<
register type="IUsuario" name="otroUsuario" mapTo="OtroUsuario" />
</
container>
</
unity>



En la parte del UI, agregamos el nuevo tipo de usuario a través de la empresa C.



private void btnLogin_Click(object sender, EventArgs e)
{
string _tipoUsuario = string.Empty;
if (cmbEmpresa.SelectedItem.ToString() == "Empresa A")
_tipoUsuario = "usuario";
else if (cmbEmpresa.SelectedItem.ToString() == "Empresa B")
_tipoUsuario = "usuarioWeb";
else
_tipoUsuario = "otroUsuario";

UsuarioActual = AdministradorUsuario.ObtenerInstancia(_tipoUsuario, txtNombreUsuario.Text, txtPassword.Text).Autenticar();

}



Si ejecutamos el código tal y como esta – y llevando la continuación del post anterior – veremos lo siguiente:



image



Como vemos en la figura, la instancia de empresa del tipo que resolvió Unity esta en nulo. Sin duda no es el comportamiento que queremos. Pero como hacer para que la clase que estamos instanciando pueda resolver la empresa que desea en tiempo de ejecución? Para este problema en específico, Unity me permite crear inyección para las propiedades con lo cual puedo definir dentro del registro del tipo para mapear, como debe de cargarse una propiedad de la clase que se va a resolver. Para lograr esto vamos a modificar nuestro archivo de configuración de la siguiente forma:



  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<
alias alias="IUsuario" type="Core.LogicaDeNegocios.IUsuario, Core.LogicaDeNegocios" />
<
namespace name="Core.LogicaDeNegocios" />
<
assembly name="Core.LogicaDeNegocios" />
<
container>
<
register type="IEmpresa" name="empresaMap" mapTo="EmpresaExterna" />
<
register type="IEmpresa" name="oficinaMap" mapTo="Oficina"
/>
<
register type="IUsuario" name="usuario" mapTo="Usuario" >
<
property name="Empresa" dependencyName ="oficinaMap" dependencyType="IEmpresa"></property
>
</
register
>
<
register type="IUsuario" name="usuarioWeb" mapTo="Usuario_Web" />
<
register type="IUsuario" name="otroUsuario" mapTo="OtroUsuario" >
<
property name="Empresa" dependencyName ="empresaMap" dependencyType="IEmpresa"></property
>
</
register
>
</
container>
</
unity>



Como podemos ver en el texto en negrita, primera vamos a crear dos mapas nuevos para los tipos recién creados que implementan la interface IEmpresa.



<register type="IEmpresa" name="empresaMap" mapTo="EmpresaExterna" />
<
register type="IEmpresa" name="oficinaMap" mapTo="Oficina" />



Seguidamente vamos a modificar los registros para los usuarios deseados y vamos a establecer la instancia que queremos sea inyectada en la propiedad del tipo de IEmpresa.



<register type="IUsuario" name="otroUsuario" mapTo="OtroUsuario" >
<
property name="Empresa" dependencyName ="empresaMap" dependencyType="IEmpresa"></property>
</
register>



      <register type="IUsuario" name="usuario" mapTo="Usuario" >
<
property name="Empresa" dependencyName ="oficinaMap" dependencyType="IEmpresa"></property>
</
register>





En este caso hemos establecido que cuando se vaya a crear una instancia del tipo Usuario la propiedad IEmpresa se instancie con el tipo Oficina, y si por lo contrario creamos una instacia del tipo OtroUsuario vamos a tener la propiedad IEmpresa con una instancia del tipo EmpresaExterna. Si creamos una instancia de Usuario_Web la instancia de la propiedad IEmpresa no se podrá resolver y por lo tanto será null.



Si seleccionamos Empresa C –> OtroUsuario el resultado será:



image



Si seleccionamos Empresa A –> Usuario el resultado será:



image



Y si seleccionamos Empresa B –> el resultado será:



image







Technorati Tags: ,,

11.23.2010

Utilizando Unity para Resolver un Problema de Negocio - 2

En el post anterior presentamos un problema el cual resolvimos usando Unity, sin embargo, este problema se presentó de una manera muy simple y un poco corto en realidad. En este post vamos a agregarle un par de situaciones que se presentan normalmente en este tipo de sistemas.

En primer lugar, cuando creamos la instancia del usuario que necesitamos, le tuvimos que indicar de forma explícita al método AdministradorDeUsuario.ObtenerInstancia utilizando un generic, algo que por supuesto no es deseado ya que obliga al cliente de la aplicación a estar conciente de los tipos de usuario que existen y esto limita la aplicación a trabajar con los usuarios existentes y no nos permite agregar nuevos usuarios sin tener que recompilar la aplicación.

En segundo lugar estamos utilizando clases para los usuarios que no contienen datos y por lo tanto no son inicializados cuando se crea la instancia, por lo que el método Autorizar no funcionaría en un escenario real ya que no tiene los datos que el usuario utilizó para loguearse.

Mejoras

Para atacar el primer problema vamos a cambiar la forma en que le solicitamos nuestras instancias a Unity. Con los contenedores de IoC tenemos la gran ventaja de que podemos solicitarles que resuelvan el tipo en base al nombre del mapeo que queremos utilizar. El primer paso es cambiar el archivo de configuración para que trabaje con un solo contenedor de la siguiente forma:

<?xml version="1.0" encoding="utf-8" ?>
<
configuration>
<
configSections>
<
section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</
configSections>
<
unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<
alias alias="IUsuario" type="Core.LogicaDeNegocios.IUsuario, Core.LogicaDeNegocios" />
<
namespace name="Core.LogicaDeNegocios" />
<
assembly name="Core.LogicaDeNegocios" />
<
container>
<
register type="IUsuario" name="usuario" mapTo="Usuario"
/>
<
register type="IUsuario" name="usuarioWeb" mapTo="Usuario_Web"
/>
</
container
>
</
unity>
</
configuration>



Seguidamente quitamos el parámetro del tipo que estamos solicitando en el método ObtenerInstancia ya que como dije anteriormente vamos a dejar que Unity resuelva el tipo en base al nombre del mapa que queremos utilizar. Los posibles nombres para los mapas son:



<register type="IUsuario" name="usuario" mapTo="Usuario" />
<
register type="IUsuario" name="usuarioWeb" mapTo="Usuario_Web" />



Además al método ObtenerInstancia le vamos a agregar dos parámetros más, el usuario y el password para que pueda agregarlos como valores al usuario que se vaya a crear – problema 2. La invocación del método desde nuestra pantalla de login ahora se ve así:



string _tipoUsuario = string.Empty;
if (cmbEmpresa.SelectedItem.ToString() == "Empresa A")
_tipoUsuario = "usuario";
else
_tipoUsuario = "usuarioWeb";

UsuarioActual = AdministradorUsuario.ObtenerInstancia(_tipoUsuario, txtNombreUsuario.Text, txtPassword.Text).Autenticar();



El siguiente paso y para trabajar en el problema 2, es crear un constructor para cada tipo de usuario de forma tal que reciba el usuario y el password como parámetros y que pueda hacer la autenticación con los mismos. Las clases modificadas son las siguientes:



public class Usuario_Web: IUsuario
{

public Usuario_Web(string pNombreUsuario, string pPassword)
{
Trace.WriteLine(string.Format("Datos del usuario. NombreUsuario: {0}, Password: {1}", pNombreUsuario, pPassword));
}


public IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario Web");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autorizar Usuario Web");
}
}



public class Usuario : IUsuario
{
public Usuario(string pNombreUsuario, string pPassword)
{
Trace.WriteLine(string.Format("Datos del usuario. NombreUsuario: {0}, Password: {1}", pNombreUsuario, pPassword));
}


public IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autenticar Usuario");
}
}



Ahora solo nos queda modificar el método ObtenerInstancia para que a través de Unity se pueda resolver el tipo que deseamos instanciar en base al tipo de usuario que queremos utilizar y además que los datos del usuario puedan ser inyectados a través del constructor de la clase a instanciar:



using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace Core.LogicaDeNegocios
{
public static class AdministradorUsuario
{
public static IUsuario ObtenerInstancia(string mapName, string pUsuario, string pPassword)
{
using (IUnityContainer container = new UnityContainer())
{
container.LoadConfiguration();
return container.Resolve<IUsuario>(mapName, new ParameterOverrides { { "pNombreUsuario", pUsuario }, { "pPassword", pPassword } });

}
}
}
}



Con esto ya podemos ejecutar nuestra aplicación y crear la instancia que deseamos con los datos enviados.



image



image



Technorati Tags: ,,,,

11.22.2010

Utilizando Unity para Resolver un Problema de Negocio - 1

En días pasados me encontré con un problema en el cual se podría utilizar IoC para resolverlo de forma sencilla y elegante. En este post voy a reproducir este fix con un problema un tanto diferente pero en el cual se puede ver como de forma sencilla podemos aprovecharnos de las bondades de Unity y a la vez hacer nuestra aplicación más versátil y fácil de hacer crecer.

El Problema

Supongamos que tenemos un sistema que hace una seria de funciones para la empresa y que luego de una fusión con otra empresa, tenemos un sistema similar pero que además realiza unas funciones extras. Resulta que cada sistema tiene su propia tabla de usuarios ( así es, como siempre primero se hacen los sistemas y luego se piensa en la seguridad y no a la inversa como debería ser ) y se quiere hacer una versión de forma rápida que mezcle las funcionalidades de ambas aplicaciones. La aplicación va a tener un ComboBox en donde el usuario indica a cual empresa originalmente pertenece y el sistema debe resolver a donde debe de ir a autenticarse el usuario. En primera instancia, la primera aplicación es desktop y la segunda aplicación es Web. El problema radica en cómo manejar estos tipos diversos de usuario en una sola aplicación sin necesidad de andar previendo con cual tipo estamos trabajando.

La Solución

La solución a este problema esta por el lado del polimorfismo, ya que si definimos una interface IUsuario, podemos trabajar con la interface y no con el tipo concreto, lo cual nos ahorraría el peso de estar manejando un tipo de usuario X en la aplicación cuando se requiera. El siguiente diagrama nos muestra lo expuesto anteriormente.

image

El código de cada una de las clases es el que se presenta a continuación:

namespace Core.LogicaDeNegocios
{
//Este usuario se autentica en una base de datos para usuarios Web
public class Usuario_Web: IUsuario
{
public IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario Web");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autorizar Usuario Web");
}
}
}



namespace Core.LogicaDeNegocios
{
//Este usuario se autentica utilizando una base de datos de usuarios locales
public class Usuario : IUsuario
{
public IUsuario Autenticar()
{
Trace.WriteLine("Autenticar Usuario");
return this;
}

public void Autorizar(object _form)
{
Trace.WriteLine("Autenticar Usuario");
}
}
}



Ahora el punto es como hacer que la aplicación construya la instancia que corresponda – dependiendo de la selección del comboBox – sin necesidad de estar creando clases concretas por toda la aplicación. Para este caso es que se decidió utilizar Unity. Con Unity tenemos la posibilidad de registrar los tipos que deseamos y mapearlos con clases concretas para cuando solicitemos el tipo, se nos retorne la instancia que deseamos. Para registrar nuestras clases anteriores vamos a utilizar el archivo app.config de nuestra aplicación desktop y vamos a agregar la siguiente configuración.



<?xml version="1.0" encoding="utf-8" ?>
<
configuration>
<
configSections>
<
section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</
configSections>
<
unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<
alias alias="IUsuario" type="Core.LogicaDeNegocios.IUsuario, Core.LogicaDeNegocios" />
<
namespace name="Core.LogicaDeNegocios" />
<
assembly name="Core.LogicaDeNegocios" />
<
container>
<
register type="IUsuario" name="usuario" mapTo="Usuario"
/>
</
container
>
<
container name="UsuarioWeb"
>
<
register type="IUsuario" name="usuarioWeb" mapTo="Usuario_Web"
/>
</
container
>
</
unity>
</
configuration>



Como podemos ver en el xml anterior, estamamos registrando dos tipos con la interface IUsuario: Usuario y Usuario_Web, para que cuando solicitemos el tipo Unity tenga como resolver y pueda crear la instancia que deseamos. El siguiente paso es utilizar el contenedor de Unity para que nos resuelva el tipo y dado que no queremos que el UI se tenga que preocupar por este block, vamos a crear una clase estática que nos ayude retornando la instancia a partir de un tipo especificado como parámetro en una función que vamos a crear para crear la instancia de acuerdo al tipo que solicita el usuario.



//Unity
using Microsoft.Practices.Unity;

namespace Core.LogicaDeNegocios
{
public static class AdministradorUsuario
{
public static IUsuario ObtenerInstancia<T>() where T:IUsuario
{
using (IUnityContainer container = new UnityContainer())
{
return container.Resolve<T>();
}
}
}
}


Nótese el constraint en el Generic, el cual nos delimita los tipos de datos que pueden ser T, en este caso T tiene que implementar IUsuario. Por último procedemos a crear el código en la forma de log in, en donde de acuerdo a la opción seleccionada por el usuario vamos a seleccionar el tipo que queremos pasar como T a la función ObtenerInstancia<T>.



IUsuario _usuarioActual;

public IUsuario UsuarioActual
{
get { return _usuarioActual; }
set { _usuarioActual = value; }
}

private void btnLogin_Click(object sender, EventArgs e)
{
if (cmbEmpresa.SelectedItem == "Empresa A")
UsuarioActual = AdministradorUsuario.ObtenerInstancia<Usuario>().Autenticar();
else
UsuarioActual = AdministradorUsuario.ObtenerInstancia<Usuario_Web>().Autenticar();

}



En este caso específico, estamos pasando el tipo concreto al método que nos devuelve una instancia de la clase solicitada, y como ambas clases deben de implementar la interface IUsuario podemos invocar el método Autenticar que es parte de este contrato. Este método nos devuelve una instancia de IUsuario el cual podemos utilizar en nuestra aplicación para operaciones posteriores de Autorización. Para cerrar el post vemos la estructura de proyecto utilizada, la cual como veremos en el siguiente post nos va a permitir cargar clases de lógica de  negocios dependiendo de la forma en que se configure el sistema.



image



Technorati Tags: ,,

11.20.2010

Actualizar una Entidad Utilizando el ObjectDataSource y el EntityFramework

Continuando con el post respecto a utilizar el EntityFramework en conjunto con el ObjectDataSource en una aplicación ASP.NET, vamos a ver como actualizar una entidad utilizando esta combinación de componentes. En primera instancia vamos a tener una tabla de usuarios la cual una vez creado el modelo en el EntityFramework vamos a tener una estructura como la que se ve en la siguiente figura.

image

Luego procedemos a crear nuestra lógica de negocio en donde vamos a tener un método que nos permite obtener una instancia única del contexto de las entidades del modelo del EntityFramework, este método lo podemos ver a continuación.

Public Class SeguridadBL
Public Shared Contexto As SeguridadEntities

Public Shared Function ObtenerContexto() As SeguridadEntities
If Contexto Is Nothing Then
Contexto = New SeguridadEntities
End If
Return
Contexto
End Function


El siguiente método es el que nos sirve para actualizar la entidad. Como podemos ver en el método, vamos a recibir una instancia de una variable tipo Usuario, la cual vamos a tener que trabajar un poco más para poder actualizar los datos en la base de datos.



    Public Function ActualizarUsuario(ByVal pUsuario As Usuario) As Integer

Dim
resultado = From u In ObtenerContexto.Usuarios _
Where u.Id = pUsuario.Id _
Select u
Dim tmpUsuario As Usuario = resultado.SingleOrDefault
tmpUsuario.Nombre = pUsuario.Nombre
tmpUsuario.Apellido1 = pUsuario.Apellido1
tmpUsuario.Apellido2 = pUsuario.Apellido2
tmpUsuario.Activo = pUsuario.Activo
tmpUsuario.Email = pUsuario.Email
tmpUsuario.Password = pUsuario.Password
Return ObtenerContexto.SaveChanges()
End Function



Como la instancia de la clase usuario que viene en el parámetro no pertence al contexto actual que estamos utilizando, vamos a tener agregarla al contexto. Sin embargo, para poder agregar la instancia, tendríamos que agregarle el entityKey, el cuál de por si ya existe en el contexto. En este caso, vamos a ir a traer la instancia utilizando una simple operación de select y luego, le vamos a setear los valores desde la instancia que viene por parámetro – en mi opinión una solución no muy elegante, pero al parecer la más practica. Pot último, le decimos al contexto que guarde los cambios en la base de datos con SaveChanges.



Del lado de la página ASP.NET, vamos a crear un objeto del tipo ObjectDataSource y vamos a proceder a configurarlo de la siguiente manera:



1. Primero seleccionamos la clase desde la cual vamos a tener el método de actualización, en nuestro caso SeguridadBL.



image



2. Luego procedemos a configurar el método de actualización. Cuando el objectDataSource detecta que el parámetro es un tipo complejo, establece la propiedad DataObjectTypeName con el nombre del tipo del parámetro el cual utiliza para crear una instancia de la clase cuando es invocado el método.



image



3. Seguidamente le asociamos el ObjectDataSource al GridView.



image



4. El siguiente paso es crear el botón de comando para tener la opción de editar.



image



Con esto finalizamos el proceso de edición utilizando el ObjectDataSource, el gridView y el EntityFramework.



image



Sin duda la ventaja principal con este esquema, es que podemos seguir utilizando nuestra lógica de negocios utilizando aplicaciones Web y através del ObjectDataSource no vamos a tener la necesidad de escribir código ni para seleccionar ni para actualizar datos.



Technorati Tags: ,,

11.16.2010

¿Qué paso aquí?–> Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0

Después de instalar VS 2010 y por consiguiente el framework 4.0 procedí a crear un servicio en WCF utilizando VS 2008, ya que el proyecto con el que vengo trabajando utiliza esta herramienta y el framework 3.5 para llevar a cabo sus tareas. Luego de crear el servicio, procedo a probarlo desde la consola del IIS 7 y plop!… me aparece el siguiente error en el browser.

image

Después de una búsqueda rápida me di cuenta que el problema esta en los application pools. Cómo se puede ver en la siguiente figura, la mayoría de mis sitios web corren sobre el application pool que esta por defecto en el IIS – DefaultAppPool – ya que normalmente uno no lo cambia hasta que lo va a sacar a producción { sin duda un tema completo para otro post ya que son muchas las ventajas de tener corriendo las aplicaciones en diferentes application pools}.

image

Cuando abrí la configuración del DefaultApplicationPool me di cuenta que este esta utilizando en framework 4.0 para ejecutar el proceso que administra mis sitios web.

image

Por supuesto, al estar creando yo mi aplicación en VS 2008, estoy en realidad utilizando el framework 2.0 y por lo tanto procedi a cambiarlo para que utilizara este framework.

image

y listo, despues de esto el sitio Web volvió a funcionar correctamente. Ahora, la pregunta que surge es ¿qué pasa si tengo que ejecutar aplicaciones en ambos frameworks? Pues bien, cuando se instala el Framework 4, se crean un par de application pools que tienen el framework configurado por defecto los cuales son los que se deben utilizar a la hora de utilizar el IIS. Nótese que existe uno integrado y otro clásico, esta diferencia se da por la forma en que queremos que IIS procese nuestros request, utilizando el esquema tradicional de IIS 6 [no recomendado], o el nuevo esquema de IIS 7+ [MUY RECOMENDADO]

image

A la pregunta de como cambiar el Application Pool de nuestra aplicación Web, se debe de ir a la aplicación web en el sitio web en que este creada, y en la parte derecha darle click a la opcoón Advanced Settings, seguidamente se selecciona la elipsis de Application Pool y se escoje el Application Pool deseado.

image

Technorati Tags: ,

11.12.2010

El patrón MVC y sus Repercusiones en las Arquitecturas Orientadas a Servicios

El patrón Model-View-Controller ha existido desde hace muchisismo años. Incluso, las aplicaciones Web que se desarrollan en Java lo implementan por defecto desde hace más de 10 años. Sin embargo, en el stack de tecnologías de Microsoft su uso se viene masificando desde la introducción del mismo con ASP.NET. Esto es una gran noticia porque nos permite aplicarle un patrón a la capa de presentación. En este post sin embargo no me voy a enfocar en las ventajas que podríamos obtener utilizando el MVC si no más bien los problemas que tendríamos si usamos el MVC de manera incorrecta.

El MVC me permite separar la lógica del negocio – dominio – de la forma en que se va a presentar al usuario la información. Esto nos da muchisimas ventajas puesto que puedo variar no solo la forma en que se presentan las pantallas, si no que también no dependo estrictamente de la tecnología que este utilizando en el UI. Algunas otras ventajas se pueden encontrar aquí. Este es el esquema generalizado del patrón MVC.

Sin embargo, cuando pensamos en aplicaciones del tipo “enterprise” tenemos que tener encuenta algunas cosas que siempre nos harán la vida más sencilla a la hora de diseñar y extender nuestras aplicaciones. Por ejemplo, nuestra lógica de negocios no siempre va ser accedida por interfaces de usuario creadas por nosotros mismos, ya que en el mundo interconectado en que vivimos es probable que nuestras organizaciones se comuniquen e integren con otras organizaciones para expander sus posibilidades de negocio, y estos partners no van a querer poner nuestro UI en las máquinas de sus agentes, sino que van a desear consumir nuestro negocios desde sus sistemas. Esto implica que debería existir un servicio – o varios – que le permitan al partner integrar sus sistemas con los nuestros. En este contexto lo ideal es que la lógica de negocios se reutilice a través de una capa de servicios tal y como se muestra en esta imágen tomada de pattern and practices y que reutilicé en un post anterior.

Esto le va a permitir al negocios ventajas tales como:

  • La empresa se asegura que todos los consumidores de la lógica de negocio, utiliza los mismos procesos o flujos, con lo cual podemos tener un proceso estandarizado para todos los usuarios del mismo.
  • Existe verdaderamente reutilización, lo que nos permite ahorrar en el costo de la implementación.
  • Cuando hay un cambio en la lógica del negocio, solo hay que llevar a cabo ese cambio en un solo lugar.
  • Aplico esquemas de autenticación y autorización de forma uniforme en el mismo sitio.
  • La integración con otras aplicaciones es más simple.
  • Interactuar con la nube es más sencillo – es decir llevar aplicaciones desde nuestro datacenters a Windows Azure por ejemplo.

En este contexto, cual sería el esquema de arquitectura que deberíamos utilizar? A continuación se presenta una esquema genérico en donde obtenemos las ventajas mencionadas anteriormente.

image

¿Y que tiene que ver esto con el MVC? Pues bien, el MVC es un patrón para la capa de UI. Esto permite como dije anteriormente crear interfaces más versátiles y más fáciles de cambiar. Sin embargo, si la interacción con la lógica de negocios no esta bien separada, vamos a terminar utilizando el controller como lógica de negocios, y en este caso vamos a quedar con toda la funcionalidad encapsulada y lista para ser utilizada exclusivamente en nuestra aplicación. Esto no esta mal si la aplicación es una unidad de negocio que no interactúa ni expone funcionalidad a otras unidades – aplicaciones – en el contexto de la empresa, lo cual es dificil de encontrar. Además, vamos a disminuir la posibilidad de reutilización ya que la funcionalidad va a queda en el sitio Web – es cierto que existen formas de accederla desde otras aplicaciones pero eso no es la idea, sino más bien lo que se busca es que este disponible directamente desde nuestros servidor de aplicaciones. En lo que respecta a mantenimiento, cualquier cambio que requiera la empresa en su funcionamiento, va a tener que ser hecho en todas las aplicaciones que de alguna forma u otra tienen que ver con el procedimiento, y siendo asi el MVC también debería tener e cambio.

Por lo tanto, el MVC en nuestra esquema anterior de arquitectura debería lucir como se ve en la siguiente figura.

image

Technorati Tags: ,

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: ,,

10.08.2010

Haciendo Sumatorias con Listas de Entidades con VB.NET

Una de las tantas excelentes funcionalidades que tienen las listas genéricas en .NET es la capacidad de hacer sumatorias basado en un predicado que se le pasa al método Sum como parámetro. Este predicado es una expresión lambda. En este post vamos a crear un par de entidades {proyecto y tarea} y vamos a proceder a crear una sumatoria en base a la relación entre estas entidades. Este post voy a desarrollarlo en VB.NET con el fin de no obligar a todos los que no programan en C# a buscar programas de traducción de código entre VB.NET y C# tal como este.

En primer lugar, vamos a crear una clase { poco – entidad } que me permita manejar cada una de las tareas de un proyecto.

Public Class Tarea
Public Property Id As Integer
Public Property
Nombre As String
Public Property
FechaInicio As DateTime
Public Property FechaFinal As DateTime

Public Sub New(ByVal pId As Integer, ByVal pNombre As String, ByVal pFechaInicio As DateTime, ByVal pFechaFinal As DateTime)
Id = pId
Nombre = pNombre
FechaInicio = pFechaInicio
FechaFinal = pFechaFinal
End Sub

Public Function
TotalHoras() As Double
Return
FechaFinal.Subtract(FechaInicio).TotalHours
End Function

End Class


En esta clase además de las propiedades – automáticas – y el constructor de la clase tenemos un método que calcula el total de horas de la tarea basado en la fecha de inicio de la tarea y la fecha final {la resta entre ambos}. La siguiente clase es la que encapsula todo el estado del proyecto.



Public Class Proyecto
Public Property Id As Integer
Public Property
Nombre As String
Public Property
FechaInicio As DateTime
Public Property FechaFinal As DateTime

Public Property TareasDelProyecto As New List(Of Tarea)

Public Sub New(ByVal pId As Integer, ByVal pNombre As String, ByVal pFechaInicio As DateTime, ByVal pFechaFinal As DateTime)
Id = pId
Nombre = pNombre
FechaInicio = pFechaInicio
FechaFinal = pFechaFinal
End Sub

End Class


En esta clase tenemos una lista de tareas, las cuales son las que al final vamos a utilizar para realizar la sumatoria a través de la clase List(of T).  Seguidamente vamos a hacer un método que nos permite crear una lista de tareas dummy para utilizarla en el proyecto.



Public Class GeneradorDeDatos
'Generar Tareas
Public Shared Function GenerarTareas() As List(Of Tarea)
Dim m_Lista As New List(Of Tarea)

Dim m_Tarea1 As New Tarea(1, "Entrevistar Usuarios", DateTime.Now, DateTime.Now.AddHours(4))
Dim m_Tarea2 As New Tarea(2, "Tabular Requerimientos", m_Tarea1.FechaFinal, m_Tarea1.FechaFinal.AddHours(4))
Dim m_Tarea3 As New Tarea(3, "Priorizar Requerimientos", m_Tarea2.FechaFinal, m_Tarea2.FechaFinal.AddHours(4))
Dim m_Tarea4 As New Tarea(4, "Filtrar Requerimientos", m_Tarea3.FechaFinal, m_Tarea3.FechaFinal.AddHours(4))

m_Lista.Add(m_Tarea1)
m_Lista.Add(m_Tarea2)
m_Lista.Add(m_Tarea3)
m_Lista.Add(m_Tarea4)

Return m_Lista
End Function
End Class


En este caso estamos utilizando el método AddHours para establecer el tiempo de cada tarea. En este proyecto en específico todas las tareas son secuenciales, es decir una tarea inicia hasta que la precede termine. Para mostrar las tareas del proyecto y para calcular el total de horas que dura el proyecto vamos a crear una pantalla igual a esta.



image



En el evento Load de la forma vamos a agregar el código necesario para poder desplegar las tareas en el grid y para poner el total de horas del proyecto en el text box de total de horas.



Public Class Form1

Property ProyectoActual As Proyecto

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ProyectoActual = New Proyecto(1, "Desarrollo de Sistema X", DateTime.Now, DateTime.Now) 'No conocemos la fecha final, no hemos agregado las tareas
ProyectoActual.TareasDelProyecto.AddRange(GeneradorDeDatos.GenerarTareas())
dgProductos.DataSource = ProyectoActual.TareasDelProyecto

'Generar el total de horas del proyecto
Dim m_TotalHoras As Double = ProyectoActual.TareasDelProyecto.Sum(Function(t As Tarea) t.TotalHoras)

txtTotales.Text = m_TotalHoras.ToString()
End Sub
End Class



Como podemos ver en la línea con negrita, estamos usando la función sum de la lista de T. Esta función recibe como parámetro un predicado el cual se va a ejecutar. En este caso no vamos a aplicar ninguna operación en la expresión lambda, pero perfectamente podríamos hacerlo. El resultado de ejecutar la forma es el siguiente.



image



Technorati Tags: ,

10.04.2010

WCF y Excepciones – Parte 2 - FaultContracts

Siguiendo con el post anterior relacionado con el manejo de excepciones en WCF en este post vamos a trabajar con excepciones personalizadas en WCF. Como vimos anteriormente, las excepciones en WCF no se propagan porque WCF no entiende de excepciones. Igualmente, debemos recordar que utilizamos Fault Messages para poder retornar un error más legible al cliente. En este post vamos a atacar el caso en donde queremos propagar la excepción lanzada en .NET desde el servicio al cliente.

Problema: Excepciones Personalizadas

Existen casos en donde por la naturaleza del error, no es posible enviar simplemente un FaultException del lado del cliente para que el mismo la maneje, si no que se requiere enviar más información de vuelta al cliente de forma encapsulada. Este tipo de excepciones es posible llevarlas a cabo en WCF utilizando los FaultContracts.

Para entender mejor la solución al problema vamos a trabajar con un ejemplo. Supongamos que deseamos enviar de vuelta un error al cliente con un código de error interno, el cual tiene un significado relevante para el cliente. Esto por supuesto sumado al código de error y a la descripción del mensaje.

En primer lugar debemos crear un contratopara representar nuestro nuevo tipo de excepción, el cual será una clase etiquetada con el Atributo DataContract para que pueda ser serializada en WCF. El código de esta clase se puede ver en el siguiente listado:

using System.Runtime.Serialization;

namespace WFCErrorManagment
{
[DataContract]
public class InvalidRequestCode
{
[DataMember]
public string InternalCodeError { get; set; }
}
}



El siguiente paso es especificar el tipo de excepción que queremos lanzar en la operación seleccionada.



[ServiceContract]
public interface IAuthenticationService
{
[OperationContract]
[FaultContract(typeof(InvalidRequestCode))]
bool AuthenticateUser(WcfUser user);
}



Con el paso anterior, vamos a tener la posiblidad de tener el tipo de la excepción del lado del cliente, es decir, el contrato de error estará del lado del cliente para su manipulación. Seguidamente procedemos a lanzar la excepción desde la implementación del servicio.



using System.ServiceModel;

namespace WFCErrorManagment
{
public class AuthenticationService : IAuthenticationService
{
public bool AuthenticateUser(WcfUser user)
{
InvalidRequestCode request = new InvalidRequestCode { InternalCodeError = "ERR1002" };
throw new FaultException<InvalidRequestCode>(request);

}
}
}



A diferencia del FaultContract del post anterior, esta vez procedemos a crear una instancia de la clase personalizada con la que vamos a manejar el error y seguidamente procedemos a lanzar una excepción generica del tipo InvalidRequestCode que es el tipo del DataContract definido para manejar el error.



Para probar el funcionamiento del código anterior, vamos a crear un cliente utilizando VB.NET – por aclamación :) – para consumir el error y manejarlo apropiadamente en el cliente. En primera instancia hacemos una referencia la servicio, seguidamente creamos una instancia del proxy y procedemos a escribir el código que nos servirá para procesar el error.



Imports WCF_BlogClient.SRExceptionTest
Imports System.ServiceModel

Module Module1

Sub Main()
Try
Dim
cliente As New AuthenticationServiceClient
cliente.AuthenticateUser(New WcfUser())

Catch ex As FaultException(Of InvalidRequestCode)
Console.WriteLine("Error invocando el servicio. Código del error: {0}", ex.Detail.InternalCodeError)
End Try


End Sub

End Module



Como pueden ver en el código anterior, tenemos acceso a la clase InvalidRequestCode que fue creada en el server, la cual sin embargo, al ser un DataContract y al ser utilizada por el FaultException termina siendo exportada al proxy para que el cliente tenga acceso a ella. Al ejecutar el código anterior con el servicio corriendo obtenemos la siguiente pantalla:



image



Technorati Tags: ,,,,

10.03.2010

Reportando Excepciones al Cliente en WCF

Uno de los problemas más comúnes a la hora de trabajar con WCF es el manejo de excepciones del lado del servicio. Es normal ver como en la implementación del servicio, el desarrollador pone un manejo de excepciones normal, basado en su conocimiento del uso de las mismas en el desarrollo de sus aplicaciones en el framework; sin embargo, a la hora de reportar la excepción el resultado no es el esperado, ya que la excepción no llega al cliente, si no mas bien llega una excepción al cliente como la que se muestra a continuación:

The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.

The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.

Server stack trace:

   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)

   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)

   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

   at IAuthenticationService.AuthenticateUser(WcfUser user)

   at AuthenticationServiceClient.AuthenticateUser(WcfUser user)

La excepción anterior fue lanzada por un servicio que simplemente lanza una excepción tal y como se puede ver en el siguiente código

public class AuthenticationService : IAuthenticationService
{
public bool AuthenticateUser(WcfUser user)
{
throw new Exception("Invalid Action");
}
}



Claramente el servicio encapsula la excepción del lado del cliente por muchas razones entre ellas seguridad. Cuando alguien quiere hackear nuestros servicios, una de las cosas que hace es invocar servicios y provocar que estos fallen para poder ver en la información que retornan las excepciones y así poder tener pistas de como “violar la seguridad” del servidor donde se hospedan nuestros servicios. Es por esto que pese a que es posible “transportar el error” al lado del cliente en WCF utilizando la directiva IncludeExceptionDetailsInFaults no es recomendable hacerlo cuando la aplicación sale a producción.



Para reproducir el error anterior basta con ejecutar el servicio en el WCF Test Client y podemos ver que aunque sabemos el tipo de excepción que vamos a lanzar, la misma nunca llega a propagarse hasta donde esta el cliente.



image



La Solución



El escenario anterior se da porque WCF fue diseñado con la interoperabilidad en mente y por esta razón utiliza SOAP Faults para manejar los errores en lugar de expceción. Para poder ser interoperables, los SOAP Fault Messages son mucho más simples que las expecpciones. Los SOAP Fault Messages tiene dos elements:





  • Code: El cual provee la información del error para comprensión a nivel de máquina – es decir, un código de error natural.




  • Reason: La misma información del error pero legible para un humano.




Si se requiere agregar información adicional acerca del error, el servicio va a tener que definir un Fault Data Contract que puede ser consumido por el cliente.



En el código siguiente se puede ver el servicio anterior pero utilizando SOAP Fault Messages.





using System.ServiceModel;

namespace WFCErrorManagment
{
public class AuthenticationService : IAuthenticationService
{
public bool AuthenticateUser(WcfUser user)
{
throw new FaultException(new FaultReason("Error Autenticando el Usuario"),
new FaultCode("Error Autenticación"));
}
}
}


A diferencia del código anterior, en este caso estamos usando la clase FaultException la cual propaga el error de forma transparente desde el servidor hasta el cliente tal y como se puede ver en la siguiente figura:



image



En el siguiente post vamos a explorar los contratos de error personalizados en WCF.



Technorati Tags: ,,