viernes, 25 de septiembre de 2009

Explorando ASP.NET MVC 2.0… Templated UI

Hola a todos!! Este post continua la mini-serie de posts que empecé con el que trataba sobre las áreas.

En este caso he estado jugando un poco con lo que llaman UI helper templating support y que me parece bastante interesante…

En el HtmlHelper han aparecido básicamente dos métodos nuevos: EditorFor<TM, TV> y DisplayFor<TM, TV>, que sirven para renderizar un editor o un visualizador para el tipo de datos TV del modelo cuyo tipo es TM.

Supongamos que tengo una clase Persona en mi modelo tal como:

public class Persona
{
    public string Nombre { get; set; }
    public int Edad { get; set; }
}



Bien, ahora en el controlador Home, en la acción Index, obtenemos un lista de objetos de dicha clase y la pasamos a la vista:


public ActionResult Index()
{
    var matusalen = new Persona()
    {
        Nombre = "Matusalén",
        Edad = 350
    };
    var jacob = new Persona()
    {
        Nombre = "Jacob",
        Edad = 32
    };
    ViewData.Model = new List<Persona>() { matusalen,jacob};
    return View();
}



En ASP.NET MVC 1.0 para mostrar los elementos tendríamos un código en la vista similar a (suponiendo una vista tipada a IEnumerable<Persona>):


<table>
<tr><th>Nombre</th><th>Edad</th></tr>
<% foreach (var persona in this.Model)
   { %>
    <tr>
        <td><%= Html.Encode(persona.Nombre) %></td>
        <td><%= Html.Encode(persona.Edad) %></td>
    </tr>
<% } %>
</table>



Algunos otros a quienes no les gustan tantos tags de servidor mezclados con código cliente se crearían una vista parcial tipada a Persona, para mostrar los datos de UNA persona:


<%@ Control Language="C#" 
Inherits="System.Web.Mvc.ViewUserControl<MvcApplication1.Models.Persona>" %>
<tr>
    <td><%= Html.Encode(Model.Nombre) %></td>
    <td><%= Html.Encode(Model.Edad) %></td>
</tr>



Y una vez tienen esta vista parcial (llamada p.ej. PersonaView) en la vista principal tendrían un código mucho más simple:


<table>
<tr><th>Nombre</th><th>Edad</th></tr>
<% foreach (var persona in this.Model)
       Html.RenderPartial("PersonaView", persona);
%>
</table>



Esta técnica (de usar una vista parcial) es la que está recomendada (especialmente si nuestro modelo tiene muchos campos)…


… y ASP.NET MVC 2, “integra” esa forma de pensar con los UI templates.


En ASP.NET MVC 2, en lugar de utilizar directamente Html.Encode para mostrar una propiedad, podemos utilizar Html.DisplayFor, que nos renderizará un “visualizador” para una propiedad de nuestro modelo. Y que tipo de visualizador renderizará? Pues para propiedades simples (tales como bools, enteros, strings) es capaz de generar el control HTML correspondiente.


P.ej. el primer paso que podríamos hacer es cojer la vista parcial PersonaView que tenemos y cambiar las llamadas a Html.Encode por llamadas a Html.DisplayFor:

<%@ Control Language="C#" 
Inherits="System.Web.Mvc.ViewUserControl<MvcApplication1.Models.Persona>" %>

<tr>
<td><%= Html.DisplayFor(x => x.Nombre) %></td>
<td><%= Html.DisplayFor(x => x.Edad) %></td>
</tr>



Fijaos en la sintaxis de DisplayFor: se pasa una lambda expresion que indica que se debe renderizar (puede ser un objeto o una propiedad del modelo). Pasar la lambda tiene un par de ventajas respecto a pasar el valor (como le pasábamos en el Encode), y es que entonces podemos utilizar reflection para inspeccionar la propiedad o clase que recibimos y ver si está decorada con determinados atributos… esto es lo que se llama DataAnnotation Support y sería tema para otro post ;-)


Bueno… la verdad es que de momento, alguien quizá se está preguntando que mejora nos aporta esto, porque más o menos tenemos un código muy parecido. La mejora viene ahora. Hasta aquí hemos utilizado DisplayFor para tipos sencillos, pero también podemos utilizarlo para tipos complejos… Es decir podemos pasar todo un objeto Persona en el DisplayFor y dejar que ASP.NET MVC decida que “visualizador” debe utilizar. Podemos modificar la vista principal para que quede:


<table>
<tr><th>Nombre</th><th>Edad</th></tr>
<% foreach (var persona in this.Model)
       Html.DisplayFor(x => persona);
 %>
</table>



Fijaos que ahora en cada llamada a DisplayFor, no le estamos pasando una propiedad del modelo (en este caso mi modelo es un IEnumerable<Persona>), sinó que le pasamos el objeto persona a renderizar. Si ahora ejecutamos nuestro código… primera decepción, ya que vemos algo como:


image


¿Que ha pasado? Pues simple: estamos viendo el comportamiento por defecto de DisplayFor cuando recibe un tipo completo: Itera sobre todas las propiedades y va mostrando su nombre y su valor… Útil, lo que se dice útil no lo es mucho… Nos queda un último paso que es configurar un UI Template para el tipo Persona, es decir indicarle a ASP.NET MVC como debe renderizar un visualizador para un objeto de tipo Persona.


Los visualizadores son siempre vistas parciales normales y corrientes (no deben implementar ninguna interfaz ni nada). En nuestro caso vamos a utilizar la vista parcial PersonaView que creamos antes. Los UI Templates en ASP.NET MVC siguen la regla de “convención antes que configuración”, eso significa que no debemos “registrarlos” en ningun sitio, sinó que implemente ASP.NET MVC va a buscarlos en una carpeta determinada… que se llama de DisplayTemplates y que está dentro de Views/Shared (para templates compartidos entre todos los controladores) o Views/<Controler> (para templates que aplican a un solo controlador).


En nuestro caso creamos la carpeta “DisplayTemplates” dentro de la carpeta Views/Home y movemos la vista PersonaView.ascx dentro de la carpeta DisplayTemplates y la renombramos como Persona.ascx (para que se llame igual que el tipo que renderiza).


Ahora si ejecutamos de nuevo la aplicación, vemos que ya se muestran bien los datos: ASP.NET MVC ha encontrado el UI Template para el tipo persona y lo ha utilizado!


Si no queremos renombrar la vista (y que se siga llamando PersonasView) entonces cuando utilizamos el DisplayFor debemos indicarle que template se debe utilizar:


Html.DisplayFor(x => persona, "PersonaView");




En el caso de Html.EditorFor todo funciona exactamente igual, salvo que la carpeta para los templates no se llama DisplayTemplates sinó EditorTemplates.


Un saludo!!!


PD: Como no puede ser de otra forma, esto es un crosspost desde mi blog en geeks.ms!

jueves, 24 de septiembre de 2009

Unity, Proxies, AOP y un poco de todo eso…

En mi opinión, usar un contenedor de IoC hoy en día, no es una opción sinó una obligación. Las ventajas que nos ofrecen son incotestables. Los patrones Service Locator y Dependency Injection nos permiten desacoplar nuestro código, y son la base para poder trabajar de forma modular y poder generar unos tests unitarios de forma más sencilla. Pero hoy no quiero hablaros de ninguno de estos patrones, sinó de otra de las capacidades de los contenedores de IoC: la generación de proxies.

Con esta técnica lo que podemos hacer es inyectar nuestro propio código para que se ejecute antes o después del código que contenga la clase en particular. Esto, si lo combinamos con los atributos nos proporciona unas capacidades potentísimas para poder tener programación orientada a aspectos.

Vamos a ver como realizar esta técnica usando Unity, pero no es exclusiva de este contenedor de IoC, otros contenedores como Windsor también tienen esta capacidad.

El mecanismo en Unity que nos permite generar proxies a partir de clases del usuario, se llama intercepción. Cuando creamos una intercepción en Unity debemos definir básicamente dos cosas:

  1. Qué ocurre cuando un método es interceptado (la política de intercepción).
  2. Cómo se intercepta un método (el interceptor).

Vamos a ver paso a paso como funciona el mecanimso.

1. Preparación del entorno

Vamos a crear una aplicación de consola, y añadimos las referencias a todos los ensamblados de Unity.

Luego vamos a crear una interfaz, y la clase que vamos a interceptar:

public interface IMyInterface
{
string SomeProperty { get; set; }
}
public class MyClass : IMyInterface
{
public string SomeProperty { get; set; }
}

Finalmente, en el método Main() creamos un contenedor de Unity y registramos el mapping entre la interfaz y el tipo:

static void Main(string[] args)
{
UnityContainer uc = new UnityContainer();
uc.RegisterType<IMyInterface, MyClass>();
}

Ahora estamos listos para empezar!!!


2. Configuración de Unity para que use un interceptor


Vamos a configurar Unity para que use un interceptor cuando se resuelva la interfaz IMyInterface. Para ello, primero debemos añadir la extensión de intercepción a Untiy y luego configurarla:

static void Main(string[] args)
{
UnityContainer uc = new UnityContainer();
uc.RegisterType<IMyInterface, MyClass>();
// Añadimos la extensión de intercepción
uc.AddNewExtension<Interception>();
// La configuramos para que nos devuelva
// un TransparentProxy cuando resolvamos IMyInterface
uc.Configure<Interception>().
SetInterceptorFor<IMyInterface>
(new TransparentProxyInterceptor());
var u = uc.Resolve<IMyInterface>();
u.SomeProperty = "test";
}

Vamos a meter un breakpoint en la última línea y a ejecutar el código, para ver si Unity ha echo algo:


image


Vaya… pues no parece que haya hecho nada, la verdad. La variable u es de tipo MyClass, no parece haber ningún proxy por ahí…


Es normal, ya que hemos configurado Unity para que use un TransparentProxy al resolver la interfaz IMyInterface, pero no lo hemos dicho que debe hacer Unity con este proxy, así que simplemente para no hacer nada, no crea ni el proxy…


3. Crear el interceptor


Ha llegado el momento de crear un interceptor, que defina que ocurre cuando se intercepta un método o propiedad de la clase. Para ello vamos a crear una clase nueva que implementa la interfaz ICallHandler:

public class MyHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
{
IMethodReturn msg = getNext()(input, getNext);
return msg;
}
public int Order { get; set; }
}

Esta es la implementación básica por defecto de ICallHandler: no estamos haciendo nada, salvo pasar la llamada a la propiedad real de la clase. Es decir, nuestro interceptor no está haciendo realmente nada.


Podemos añadir aquí el código que queramos, p.ej:

public IMethodReturn Invoke(IMethodInvocation input, 
GetNextHandlerDelegate getNext)
{
Console.WriteLine("Se ha llamado {0} con valor {1}",
input.MethodBase.Name, input.Inputs[0]);
IMethodReturn msg = getNext()(input, getNext);
return msg;
}

4. Indicar que métodos / propiedades queremos interceptar


Tenemos a Unity configurado para usar intercepción, y un interceptor creado… ahora nos queda finalmente vincular este interceptor con las propiedades o métodos que deseemos.


Para ello podemos usar los atributos: la idea es decorar cada propiedad o método con un atributo que indique que interceptor se usa para dicha propiedad y además configure dicho interceptor. Así, generalmente, vamos a usar un atributo para cada interceptor. En nuestro caso tenemos un sólo interceptor (MyHandler), así que añadiremos un atributo MyHandlerAttribute.


Para ello vamos a crear una clase que derive de HandlerAttribute (la cual a su vez deriva de Attribute), y redefinir el método CreateHandler. En este método debemos devolver el Handler que deseemos:

[AttributeUsage(AttributeTargets.Property)]
class MyHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler
(IUnityContainer container)
{
return new MyHandler();
}
}

En este caso nuestro atributo es trivial, pero en otros casos el atributo puede tener parámetros (y pasárselos al constructor del interceptor, o incluso crear un interceptor u otro en función de dichos parámetros).


5. Aplicar el atributo a las propiedades que deseemos


Para ello simplemente decoramos las propiedades (o métodos) que deseemos con el atributo:

public class MyClass : IMyInterface
{
[
MyHandler]
public string SomeProperty { get; set; }
}

Y…. ya hemos terminado! Si colocamos un breakpoint en el mismo lugar de antes, veremos que ahora si que Unity nos ha creado un proxy:


image


Y si ejecutamos el programa, veréis como la salida por pantalla es la siguiente:





Se ha llamado set_SomeProperty con valor test

Nuestro interceptor ha sido llamado… hemos triunfado!!! ;-)


Si añadís una propiedad extra a la interfaz (y a la clase) y NO la decoráis con el atributo veréis que, obviamente dicha propiedad NO es interceptada.


Esta técnica tiene unas posibilidades brutales… a mi se me ocurren a brote pronte, temas de logging, seguridad, validación de propiedades… vamos, todo aquello en lo que es aplicable la programación orientada a aspectos!


Un saludo a todos! ;-)


PD: Esto es un crosspost de mi blog en geeks.ms

martes, 22 de septiembre de 2009

Explorando ASP.NET MVC 2.0… áreas

No hace mucho Jorge Dieguez comentaba la salida de ASP.NET MVC 2.0 Preview 1. He estado investigando un poco las novedades del framework, y hoy quiero hablaros de lo que se conoce como áreas.

Cuando hablamos de áreas no nos referimos a zonas de la pantalla (tipo webparts) sinó que las áreas en ASP.NET MVC permiten construir una aplicación en base a módulos. Actualmente en la preview 1, el sistema consiste en:

  • Definir la área principal: Un proyecto ASP.NET MVC completo, con sus vistas, sus controladores, sus hojas de estilo, …
  • Definir el resto de áreas (módulos). Cada área es un proyecto ASP.NET MVC que añade sus propias vistas y controladores. Cada área confía en el área principal para el resto de temas (p.ej. scripts y css están en el área principal). De igual modo toda la inicialización (global.asax) se realiza únicamente en el área principal: el resto de áreas no tienen global.asax.

De esta manera se pretende poder gestionar mejor grandes aplicaciones: al estar formadas por áreas independientes, que a su vez son proyectos independientes de ASP.NET MVC, equipos distintos podrían realizar cada una de las áreas.

En el archivo global.asax, del área principal, cuando registramos las rutas, mapeamos determinadas URLs a cada uno de las áreas. Imaginad que tenemos una área que contiene toda la parte de administración del sitio, podríamos añadir a global.asax, una línea tal como:

routes.MapAreaRoute("Admin", "Admin_Default", 
"admin/{controller}/{action}/{id}",
new string[] { " Admin.Controllers" });



El primer parámetro es el nombre del área (luego veremos que el nombre tiene implicaciones), el segundo el nombre de la ruta (cada área puede tener tantas rutas como se desee), el tercer parámetro es la URL a enrutar y el cuarto parámetro es un array con todos los namespaces donde buscar los controladores.



De esta manera todos las URLs que empiecen por /Admin/ serán enrutadas a la área Admin. P.ej. la URL /Admin/Users/View/20 sería enrutada al controlador “UsersController”, llamando a su acción View con el Id de 20. El último parámetro (un array de strings) es importante puesto que contiene todos los namespaces de los posibles controladores de la área de administración. Dado que son proyectos distintos pueden tener controladores con el mismo nombre, así que el motor de ASP.NET MVC debe saber el namespace a utilizar… En fin, que simplemente le estamos diciendo al motor de ASP.NET MVC que use el controlador que sea que esté en el namespace Admin.Controllers.



P.ej. en mi caso estoy trabajando con 3 áreas (la principal y dos más) y tengo definida la siguiente tabla de enrutamiento:



routes.MapAreaRoute("Game", "Game_Default", 
"game/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new string[] { "Game.Controllers" });
routes.MapAreaRoute(
"Admin", "Admin_Default", "admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new string[] { "Admin.Controllers" });
routes.MapAreaRoute("Main",
"Main_Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new string[] { "Web.Controllers" });



Todas las URLs que empiecen por /Game/ se enrutarán al área que implementa la aplicación web en sí (efectivamente es un juego :p), mientras que todas las URLs que empiecen por /Admin/ se enrutarán al área que implementa la zona de administración. Finalmente el resto de URLs (que no empiecen ni por /Game/ ni por /Admin/ serán enrutadas al área principal. Fijaos que las 3 áreas definen un controlador “Home” pero no es problema, puesto que el namespace es distinto :)



Obviamente se puede generar un enlace desde una área a otra (sino maldita la gracia). Así de esta manera se genera un enlace a la acción About del controlador Home de la área actual:



<%= Html.ActionLink("Pulse aquí", "About", "Home") %>



En fin, como siempre… Para cambiar de área simplemente debemos pasar el nombre del área (debe usarse el mismo nombre con el cual se ha registrado el área en MapAreaRoute):



<%= Html.ActionLink("Pulse aquí", "About", "Home", 
new { area = "Game" } , null)%>



Esto genera un enlace a la acción About del controlador Home del área Game (en mi caso una URL tipo /Game/Home/About).



Todo muy bonito pero…



… estamos en una preview 1, así que no todo es tan directo.



Imaginad el caso del enlace que he puesto que genera una URL a la acción About del controlador Home del área Game. Imaginad que el código de la acción About de dicho controlador es:



public ActionResult About() { return View(); }



Esto debería retornar la vista que està en Views/Home/About.aspx del proyecto que es el área Game… Pues no :( Esto utiliza la vista que está en Views/Home/About.aspx del proyecto que es el área principal. Si el área principal no tiene esta vista todo rebienta. Obviamente este comportamiento ni es correcto (cada área debe proporcionar sus propias vistas) ni útil ya que si de todos modos el proyecto del área principal debe contener todas las áreas… donde está la capacidad de poder modularizar el desarrollo?



Bueno, todo esto viene debido a que estamos en preview 1, y simplemente debemos cambiar la configuración de los proyectos. Si editamos los ficheros .csproj de cada aplicación web, veremos primero unas líneas como estas (que como nos indican debemos descomentar):



<!-- To enable MVC area subproject support, uncomment the following two lines:
<UsingTask TaskName="Microsoft.Web.Mvc.Build.CreateAreaManifest"
AssemblyName="Microsoft.Web.Mvc.Build, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
<UsingTask TaskName="Microsoft.Web.Mvc.Build.CopyAreaManifests"
AssemblyName="Microsoft.Web.Mvc.Build, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
-->



y luego otras como las siguientes (que debemos descomentar según el proyecto sea el área principal o no):



<!-- If this is an area child project, uncomment the following line:
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child"
AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)"
ContentFiles="@(Content)" />
-->
<!--
If this is an area parent project, uncomment the following lines:
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent"
AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)"
ContentFiles="@(Content)" />
<CopyAreaManifests ManifestPath="$(AreasManifestDir)"
CrossCopy="false" RenameViews="true" />
-->



Así pues ya vemos lo que se debe hacer, no? ;-) Descomentamos en cada proyecto las líneas que pertoquen y listos!



Esto básicamente lo que hace es establecer una custom action build que copia las vistas de las áreas hijas dentro de la carpeta Views del área principal. De esta manera dentro de la carpeta Views del área principal tendremos:



Views/Home/About.aspx –> Vista para la acción Home.About del área principal



Views/Areas/Game/Home/About.aspx –> Vista para la acción Home.About del área “Game” (copia de la vista Views/Home/About.aspx) del proyecto que es el área Game.



Nota Importante: Para que todo esto funcione el nombre del área debe corresponderse con el nombre del ensamblado del proyecto que genera dicha área. En mi caso, el proyecto del área “Game” debe generar el ensamblado Game.dll. Si el nombre del área y el nombre del ensamblado del proyecto es distinto, no funcionará porque…



… el motor de ASP.NET MVC usa el nombre del área (definido en la llamada a MapAreaRoute)



…y en cambio la vista estará copiada en Views/Areas/<NombreAssembly>



Si no quereis que el assembly se llame igual que nombre del área podeis modificar la línea:



<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" 
AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)"
ContentFiles="@(Content)" />



que hemos descomentado antes y poner en AreaName el nombre lógico del área (el que habéis usado en RegisterMapRoute). De todos modos aunque funciona no os lo recomiendo ya que entonces las vistas de este ensamblado se duplican dentro de Views/Areas… es decir se siguen copiando como Views/Areas/<NombreAssembly> y además como View/Areas/<NuestoNombreDeArea>… o sea que lo más práctico es que los assemblies se llamen como las áreas y listos :)



Toda esta paranoia de editar el fichero de proyecto desaparecerá en futuras versiones donde tendremos un template de proyecto para aplicación ASP.NET MVC “área principal” y otro para “área hija”… recordad: preview 1 ;-)



En fin… espero que esto os haya servido para ver un poco que son las áreas en ASP.NET MVC 2.0 Preview 1. Resumiendo:




  • Una área es un proyecto de ASP.NET MVC 2.0 que implementa parte de una aplicación entera (p.ej. el módulo de administración)


  • Una aplicación ASP.NET MVC 2.0 se compone de una (y sólo una) área padre y varias áreas hijas (una por módulo)


  • El área padre proporciona los estilos (css) y ficheros de javascript, así como la inicialización/finalización de la aplicación (global.asax). Puede también proporcionar vistas y controladores


  • Las áreas hijas proporcionan vistas y controladores adicionales


  • El método MapAreaRoute sirve para enrutar determinadas URLs a los controladores de una área determinada


  • Todo está bastante verde todavía pero bueno… :)



Saludos!!!



PD: Esto es otro crosspost desde mi blog en geeks.ms!

jueves, 17 de septiembre de 2009

Como independizar tu capa de lógica de tu capa de presentación…

A raiz del siguiente post del excelente blog de Oskar, Julio Trujillo comentó en un comentario (copio literalmente) “Sería interesante una explicación de como convertir Forms a WPF o al menos como poder diseñar una capa que permita conectar la capa de negocio a una de WPF o Forms indistintamente”. A este comentario respondí yo con unas cuantas ideas, pero luego Julio pidió a ver si podiamos exponer las “buenas prácticas” e incluso un ejemplo… Julio, no respondí a tu comentario, simplemente porque el tema es demasiado para un simple comentario, y se merece al menos un post… y estaba sacando tiempo ;)

Creo que el comentario de Julio, encerraba dos preguntas en una: cómo se puede convertir fácilmente nuestras aplicaciones winforms a wpf y por otro como reaprovechar el máximo código posible. Voy a exponer unas cuantas ideas que quizá os pueden ayudar pero que se resumen en dos: usad una arquitectura n-layer (por cierto que nosotros hablamos sólo de “n-capas” pero no confundais n-layer con n-tier), por un lado y el patrón separated presentation por el otro…

Arquitectura n-layer

En esta arquitectura, básicamente, distribuimos nuestro código en n-capas lógicas, donde n suele tener un valor cercano a 3: la separación clásica es presentación, lógica y datos. Aunque se pueden meter más (o menos, igual podemos prescindir de la capa de datos) capas lógicas (como p.ej. lógica de presentación).

Una arquitectura n-layer nos ayudará a reaprovechar nuestro código de la capa lógica con independencia de la capa de presentación que tengamos… Para ello basta seguir dos reglas que nos indicarán si vamos por buen camino:

  1. Nuestra capa de lógica debe estar en un proyecto separado (una librería de clases). Puede haber (y generalmente habrá) una referencia desde el proyecto que sea la capa de presentación al proyecto que es la capa de lógica pero nunca debe aparecer una referencia a la capa de lógica que vaya hacia la capa de presentación.
  2. El proyecto que contiene nuestra capa lógica no debe tener nunca ninguna referencia a ningún ensamblado de .NET que dependa, directa o indirectamente, de Winforms o WPF… P.ej. si te aparece una referencia a System.Windows.Forms… mal, porque estás ligando tu capa de lógica a una tecnología de presentación.

La comunicación desde la capa de presentación a la capa lógica puede ser acoplada: lógico, disponemos de una referencia en la capa de presentación a la capa lógica y por lo tanto podemos instanciar cualquier clase pública de la capa de lógica y llamar a sus métodos directamente.

La comunicación desde la capa lógica a la capa de presentación debe ser desacoplada: no tenemos otra opción, dado que no podemos tener ninguna referencia a la capa de presentación desde la capa lógica. Aquí tenemos tres alternativas válidas:

  1. Comunicación pasiva: es decir, la capa de lógica se limita a devolver toda la información que la capa de presentación solicita mediante los valores de retorno de los métodos. Así, la comunicación la inicia siempre la capa de presentación.
  2. Eventos, o cualquier mecanismo similar (como commands): Cuando la capa de lógica quiere informar de algo a la capa de presentación, lanza eventos a los que está suscrita la capa de presentación y esta actúa en consecuencia. Esto permite que la capa lógica realice envíos de información a la capa lógica sin ser necesario que esta última inicie la comunicación.
  3. Utilizar interfaces junto con un patrón service locator. Esta alternativa precisa el uso de un contenedor IoC (como Unity o Windsor), así como la aparición de un tercer assembly destinado a contener las interfaces. Usando esta aproximación, las clases de la capa de presentación implementan todas ellas las interfaces (definidas en el assembly aparte) y la capa de lógica obtiene referencias a los objetos de la capa de presentación usando las interfaces y el contenedor de IoC. Esta alternativa permite una conversación “tu-a-tu” con la capa de presentación.

Por supuesto las tres alternativas pueden combinarse.

Esto independiza nuestra capa de lógica (y de datos) de la presentación usada. Si alguna vez queremos migrar nuestra aplicación, p.ej. de winforms a wpf, sólo deberemos reescribir la capa de presentación… lo que según como esté diseñada puede ser un trabajo asumible o una obra de titanes.

Separated Presentation

Bajo este nombre se agrupan multitud de patrones (MVC, MVP, MVVM), pero todos ellos coinciden en lo básico: separa siempre tu código que muestra los datos (el formulario) del código que indica cuando y como debe mostrarlos.

Lamentablemente, desde los tiempos de Visual Basic, Microsoft nos acostumbra a desarrollar usando el “patrón formulario”, que básicamente consiste en crear un form, rellenar-lo de controles y asociar eventos a funciones tipo MyButton_Click() que contendrán todo el código. Este modelo es rápido, fácil de entender y produce buenos resultados… hasta que uno debe empezar a cambiar cosas. A lo mejor al cabo de unos meses en tu aplicación le aparece otro formulario que se parece mucho a un formulario ya existente pero a lo mejor muestra un par de controles más o se comporta ligeramente distinto… O bien haces copy-paste del primer formulario en uno nuevo y lo modificas (funciona pero luego vas a mantener dos formularios parecidos) o empiezas a meter ifs en el primer formulario hasta que todo se vuelve un galimatías.

Créeme: Olvida el “patrón formulario” cuanto antes. Sirve para pequeñas aplicaciones que no precisen un mantenimiento excesivo, pero para aplicaciones mayores usa alguna variante de separated presentation.

Si nos centramos en el caso concreto de Winforms y WPF, una de las mejores elecciones es MVP: si ya sabes que tu aplicación deberá ser migrada (o bien debe ser multi-presentación) entonces MVP te ahorrará bastante trabajo: “básicamente” sólo deberás rediseñar los formularios y podrás aprovechar el modelo y los presenters. Yo por ejemplo suelo usar siempre MVP cuando desarrollo en Winforms (no por temas de migración, sino porque considero que es el patrón que aplica mejor) y cuando estoy en WPF uso MVVM o MVP dependiendo de la ocasión.

Reconozco que si se debiera migrar una aplicación WPF creada usando MVVM a winforms habría bastante trabajo, pero de todos modos muchas veces si se migra una aplicación a una tecnología de presentación nueva es para aprovechar las nuevas capacidades (me cuesta imaginarme una migración de WPF a winforms, mientras que al revés puede ser más habitual).

En fin, migrar una aplicación a otra tecnología de presentación siempre cuesta trabajo, pero si separamos bien las capas (n-layer) y organizamos bien nuestra capa de presentación (separated presentation) tendremos mucho de ganado…

Saludos!!!!

PD: Esto es (para variar) un crosspost de mi blog en geeks.ms!

miércoles, 9 de septiembre de 2009

La odisea de conectar mi portátil a mi televisor…

Esta es una historia de como el desconocimiento de unos (el mío) y de otros (los de la tienda) convierte en una odisea algo que debería ser mucho más sencillo… y que sin embargo tampoco es lo simple que debiera.

Me explico: Llevo ya 3 viajes a la tienda de cables (vamos a llamarla así) para encontrar un modo de conectar mi portátil (un latitude e6400) a mi televisor Philips de pantalla plana. Es decir  ni el portátil ni el televisor son del año de la maría castaña (aunque el televisor no sea full hd, sólo hd ready). Soy (o mejor dicho era) un auténtico ignorante en materia de conexiones, cables, señales y demás. Jamás me había importado este tema hasta ahora… pero esto no debería ser un problema, uno supone que cuando va a comprar algo quien le vende el producto debe ser capaz de informarle… iluso.

Viaje 1: Intento de conexión a HDMI

Mi televisor tiene entrada HDMI, y esa es la entrada que yo me planteé utilizar para la conexión… total se supone que HDMI es la repera, así que vamos a usarla, no? Bien, voy a la tienda y digo que quiero conectar mi portátil, que sólo tiene salida VGA, a la entrada HDMI de mi televisor. Me dicen que no hay adaptador VGA a HDMI (es cierto) pero que si que lo hay de VGA a DVI y luego de DVI a HDMI. Así que compro el cable VGA –> DVI y luego el adaptador DVI a HDMI (mi televisor no tiene entrada DVI). Llego a casa, lo conecto… y no va.

Luego (como siempre sólo busco información cuando las cosas fallan :p), me entero de que es imposible enchufar una señal VGA a una entrada HDMI sin mediar por medio un conversor de señal. La razón? VGA es analógica y HDMI es digital… así que o bien se digitaliza la señal proveniente de la VGA o nada de nada.

Entonces… por que existen cables VGA –> DVI y adaptadores DVI a HDMI? Google me dio la respuesta: Resulta ser que existen tres tipos de cables DVI: DVI-A, que transporta señal analógica, DVI-D, que transporta señal digial y DVI-I que puede transportar ambas señales pero no puede realizar una conversión. Es decir, con un cable DVI-I puedo conectar un DVI-A con una entrada analógica o bien un DVI-D con una entrada digital, pero no puedo conectar un DVI-D con un DVI-A (por ejemplo). HDMI por su parte es sólamente digital, los conversores HDMI estan pensados para convertir a HDMI una entrada DVI-D, o DVI-I siempre que transporte señal digital.

Viaje 2: De VGA a RGB (RCA)

Finalmente miré el manual de la tele, y mira por donde hay un apartado que dice cómo conectar una salida VGA a la tele… según ellos debe usarse un cable VGA –> RGB H/V. Total que me fui a la tienda y terminé llevándome un cable VGA –> RGB. Reconozco que no estaba muy convencido, porque según el manual el cable VGA –> RGB H/V tiene cinco pins para conectar a la tele, pero el cable que me dieron solo tenía tres pins: uno verde, uno azul y el otro rojo. Y los conecté a la entrada verde, azul y roja del televisor… y no se veía nada :(

Todavía hoy no se cual es la diferencia entre un cable VGA –> RGB y un cable VGA –> RGB H/V (bueno, se supone que los dos pins addicionales son para el sincronismo horizontal y vertical). Pero bueno… un cable VGA –> RGB no funciona, aunque ha sido con el que más me he acercado… he llegado a intuir la imagen, aunqué toda rosada y moviendose continuamente… por más que he cambiado la resolución y/o la frecuencia de refresco no he conseguido nada.

Viaje 3: De VGA a Euroconector (SCART)

De nuevo a la tienda, dispuesto a hablar con el dependiente que me había atendido las otras dos veces para decirle a ver si tenía el cable RGB H/V de las narices… pero no estaba. Así que de nuevo conté que tenía un portátil con salida VGA y una tele que no tenia entrada VGA y que el cable VGA –> RGB no me había funcionado. Le pregunté por el cable VGA –> RGB H/V pero su cara fue un poema… Me dijo que nunca había visto ese cable y me preguntó si mi tele tenía entrada por euroconector, a lo que yo le respondí que sí y el me dijo que entonces ningún problema y me dio un cable VGA a euroconector. Y yo me lo llevé, aunque en mi descargo debo decir que no muy convencido.

Y evidentemente, no funcionó… Luego, leyendo por ahí, he visto que este cable sólo funciona si el emisor (o sea mi portátil) emite en la misma frecuencia y resolución que espera la tele, o sea PAL. Me peleé un rato con el portátil, a ver si podia hacer que emitiese en PAL, pero nada de nada… Probé desde 640x480 con 50/60 Hz hasta 1024x768 y nada de nada… :(

En fin…

Hoy, si puedo, iré a otra tienda que aunque me cae bastante más lejos, entienden un poco de lo que venden, a ver como narices puedo conectar mi portátil sin morir en el intento. Hay gente que comenta que con un cable de VGA a video por componentes funciona… El cable VGA a video por componentes es de aspecto idéntico al cable VGA –> RGB que ya probé: también tiene tres conectores de colores, salvo que en lugar de llamarse R, G y B se llaman Y, Cb y Cr (o Y, Pb, Pr si estamos en analógico). Lo que me “escama” un poco es que el manual de la tele sí que menciona que puede conectarse un cable de video por componentes, pero cuando hablan de un portátil con salida VGA, se olvidan de ese cable y entonces sólo hablan del famoso RGB H/V (el video por componentes lo mencionan cuando hablan de conectar DVDs o videos).

A ver que comentan en la tienda… :)

En fin… lo que sí me ha quedado claro de todo esto es que el próximo portátil que me pille, a poco que pueda, va a tener salida DVI-D o HDMI…

Saludos!

PD: Esto es un crosspost de mi blog en geeks!

lunes, 7 de septiembre de 2009

STM.NET: Software Transactional Memory (ii)

Hola a todos! En el post anterior os comenté algunas cosillas sobre STM.NET, un “experimento” de los DevLabs de Microsoft para introducir conceptos transaccionales dentro de .NET. En este segundo post quiero extenderme un poco más con algunos ejemplos un pelín más elaborados.

Ejemplo 3

En el ejemplo 2 (del post anterior) vimos como lanzar una excepción dentro de una transacción definida por Atomic.Do() hacía un rollback de todos los cambios producidos dentro de la transacción. Vamos a verlo con más detalle.

Empezamos por definir una clase “Cuenta” para permitir ingresar o quitar determinadas cantidades de dinero:

class Account
{
public Account(int saldoInicial)
{
Saldo = saldoInicial;
}
public int Saldo { get; private set; }
public void Ingreso(int i)
{
Saldo += i;
}
public void Dispensacion(int i)
{
Saldo -= i;
if (Saldo < 0)
throw new Exception(
string.Format("Error al sacar {0} eur", i));
}
}

Es una clase normal de .NET, sin ninguna otra particularidad. Ahora vamos a hacer un programilla para permitir ir haciendo transferencias de una cuenta a otra:

class Program
{
[AtomicNotSupported]
static void Main(string[] args)
{
Account cuentaDestino = new Account(0);
Account cuentaOrigen = new Account(100);
Console.WriteLine("=== INICIO ===");
Console.WriteLine("Destino {0} eur", cuentaDestino.Saldo);
Console.WriteLine("Origen {0} eur", cuentaOrigen.Saldo);
int transferir = 0;
do
{
transferir = 0;
Console.WriteLine("Entrar fondos a transferir...");
string s = Console.ReadLine();
int valor;
if (int.TryParse(s, out valor))
{
transferir = valor;
try
{
Console.WriteLine
("=== Transfiriendo {0} eur ===",
transferir);
Transferencia(cuentaOrigen, cuentaDestino,
transferir);
}
catch (Exception ex)
{
Console.WriteLine("ERROR en transferencia: {0} ",
ex.Message);
}
}
Console.WriteLine("=== SALDOS ===");
Console.WriteLine("Destino {0} eur", cuentaDestino.Saldo);
Console.WriteLine("Origen {0} eur", cuentaOrigen.Saldo);
} while (transferir != 0);
}
static void Transferencia(Account origen, Account destino,
int qty)
{
destino.Ingreso(qty);
origen.Dispensacion(qty);
}
}

Más simple el agua… El programa va haciendo transferencias de una cuenta a otra. Aquí teneis la salida del programa después de varias ejecuciones:





=== INICIO ===
Destino 0 eur
Origen 100 eur
Entrar fondos a transferir...
120
=== Transfiriendo 120 eur ===
ERROR en transferencia: Error al sacar 120 eur
=== SALDOS ===
Destino 120 eur
Origen -20 eur
Entrar fondos a transferir...

Al hacer la transferencia de 120, nos salta la excepción (capturada correctamente por la función Main), pero hay dos problemas:



  1. Los 100 euros se han ingresado ya en la cuenta de destino
  2. La cuenta de origen se ha quedado en –20

El punto (1) es debido a como se ha codificado la función Transferencia (que primero hace el ingreso y luego el cargo) y el punto (2) es debido a que la función Account.Dispensacion quita el dinero primero y lanza la excepción después. Vale, con un par de ifs esto se arregla, pero es un buen punto de partida para ver como funciona STM.NET.


Aquí está claro que una transferencia es una operación atómica: O bien se hace el cargo y luego el abono, o bien no se hace nada. Si es una operación atómica, lo ideal es ejecutarla dentro de un Atomic.Do(). Podemos modificar la función Transferencia, para que quede con el siguiente código:

static void Transferencia(Account origen, Account destino, 
int qty)
{
Atomic.Do(() =>
{
destino.Ingreso(qty);
origen.Dispensacion(qty);
});
}

Si ahora ejecutamos el programa la salida que tenemos es:





=== INICIO ===
Destino 0 eur
Origen 100 eur
Entrar fondos a transferir...
120
=== Transfiriendo 120 eur ===
ERROR en transferencia: Error al sacar 120 eur
=== SALDOS ===
Destino 0 eur
Origen 100 eur
Entrar fondos a transferir...

La llamada a origen.Dispensacion genera una excepción que provoca que se haga un rollback. El rollback afecta tanto a la cuenta de destino (a la cual ya se le habían ingresado los 120 euros) como a la cuenta de origen (a la cual ya se le habían quitado los 120 euros, quedando en negativo).


Simple, sencillo y elegante.


Ejemplo 4: Supresión parcial de una transacción


Dentro de una transacción el código que se ejecuta debe estar preparado para ejecutarse en una transacción. Hay métodos que por su naturaleza no pueden ser transaccionales (porque realizan efectos visibles al usuario). P.ej el siguiente código falla:

Atomic.Do(() =>  Console.WriteLine("Hola Mundo"));

Lanza una excepción AtomicContractViolationException indicando que Console.WriteLine se accede dentro de un bloque transaccional pero está marcado con el atributo [AtomicNotSupported] indicando que no se soportan transacciones.


A veces (p.ej. para depurar) nos puede interesar llamar a métodos que no soportan transacciones (y por lo tantos marcados mediante [AtomicNotSupported]). En este caso debemos encapsular las llamadas a este método desde otro método, decorado con [AtomicSupress]. El atributo [AtomicSupress] suspende temporalmente la transacción. En este caso deberíamos tener el siguiente código:

[AtomicSupported, AtomicSuppress]
public void Log([AtomicMarshalReadonly] string msg)
{
Console.WriteLine(msg);
}

El atributo [AtomicSupported] indica que el método Log soporta ser llamado desde una transacción, mientras que el atributo [AtomicSuppress] lo que hace es suspender la transacción de forma temporal, permitiendo así que dentro del método Log se llamen a métodos decorados con [AtomicNotSupported] como Console.WriteLine.


Si el método recibe referencias a objetos creados dentro de la transacción, estas referencias deben ser serializadas (código fuera de transacción no puede acceder directamente a referencias creadas dentro de código transaccional). Por suerte para nosotros de este trabajo se puede encargar STM.NET: sólo debemos decorar el parámetro con el atributo [AtomicMarshalReadonly].


Ejemplo 5: Integración con LTM i DTC


Las transacciones iniciadas con STM se integrarán con LTM y DTC:

Atomic.Do(() =>
{
// Operaciones en memoria
// Operaciones sobre BBDD
// Otras operaciones (p.ej MSMQ)
});

La transacción se inicia como una transacción interna de STM (relativamente poco costosa y cuando sea necesario (p.ej. llamada a BBDD o MSQM) se promocionará a una transacción LTM (que a su vez puede ser promocionada de nuevo a una transacción DTC).


De todos modos esa funcionalidad está todavia en desarrollo y funciona sólo para el caso de MSMQ: no es posible usar (de momento) ADO.NET dentro de Atomic.Do() aunque obviamente es algo que está previsto.


Ejemplo 6: Compensaciones


No siempre es posible hacer un rollback: hay veces que una acción tiene efectos visibles inmediatos y no es posible deshacerlos sin que el usuario se entere. En este caso lo que se hace en el rollback es hacer otra acción que compense la acción que se quiere anular. Esto rompe el concepto de “Isolación” ya que el usuario percibe operaciones que no debería percibir (la priemra acción y la acción de compensación), pero en muchos casos es la única alternativa posible.


STM proporciona soporte para comensaciones, usando el método Atomic.DoWithCompensation(). Este método toma dos delegates, con la acción a realizar y la acción de compensación. La acción a realizar se ejecuta de inmediato y la acción de compensación se ejecutará siempre que sea necesario hacer un rollback de la acción. Ambas acciones se ejecutan dentro de un contexto decorado con [AtomicSupress], por lo que pueden llamar a métodos que no soporten transacciones.


Dicho esto… no he conseguido hacer funcionar Atomic.DoWithCompensation(). Intente lo que intente me da una excepción (System error) y ocasionalmente una NullReferenceException. Incluso el propio ejemplo que viene con STM.NET me da esos errores… igual se me está pasando algo por alto :(


Resumen


Bueno… espero que este post, junto con anterior os hayan servido para comprender un poco que es STM.NET. Recordad que es un proyecto de DevLabs y por lo tanto no es, ni mucho menos, un producto terminado (de hecho, su licencia prohibe usarlo para realizar s/w que deba ir en producción)… El tiempo dirá si algunas, o todas, de sus ideas las terminamos viendo en alguna versión del Framework ;-)


Página principal de STM.NET


STM.NET versus TransactionScope

miércoles, 2 de septiembre de 2009

STM.NET: Software Transactional Memory

Uno de los retos más importantes a los que se enfrenta en breve el desarrollo de aplicaciones tiene que ver con la programación paralela. Ahora que se empieza a vislumbrar el acercamiento del fin de la Ley de Moore, si queremos seguir el espectacular aumento de potencia debemos irnos a entornos multi-procesador o multi-core. Hace unos años eran coto reservado a entornos de investigación, y ahora ya están encima de nuestra mesa…

Hay varias visiones sobre como se debe atacar este problema, cual debe ser el rol del desarrollador, de los frameworks y del sistema operativo para asegurar una buena productividad y a la vez ser capaz de asegurar un óptimo consumo de los distintos recursos. Como dijo Rodrigo una vez… La Broma ha terminado!

La versión 4.0 del framework trae novedades al respecto, en concreto las famosas Parallel Extensions (que también pueden descargarse para funcionar con el framework 3.5), que permiten un nivel de abstracción más alto y facilitan el uso de la programación concurrente. Se ha hablado largo y tendido en geeks sobre las parallel.

Por otro lado, hace ya bastante tiempo que Microsoft tiene el DevLabs, una especie de laboratorio de investigación de donde salen proyectos de investigación que en un futuro pueden ver la luz (como productos independientes o bien integrándose en otros como puede ser .NET Framework). Del DevLabs han salido cosas tan interesantes como Code Contracts (de las que ya he hablado en este mismo blog), Pex, Small Basic (una versión de Basic para aprender a programar) y lo que os quiero comentar en este post: STM.NET.

¿Que es STM.NET?

STM.NET son unas extensiones sobre el framework 4.0 que implementa el concepto de Software Transactional Memory, un mecanismo que nos permite aislar zonas de código para que se ejecuten de forma segura en un entorno multiprocesador. STM.NET no ofrece nuevas abstracciones sobre tareas concurrentes (como hacen las Parallel) sinó que se centra en como proteger las zonas de código compartido. Evidentemente esto no es nuevo, .NET ya ofrece un mecanismo para la protección de código compartido: los locks y toda una pléyade de clases para la sincronización de threads.

¿Entonces para que STM?  STM ataca el problema desde otro punto de vista: usando el concepto de transacciones. En concreto de las propiedades ACID (atomicidad – atomicy, coherencia – consistency, aislamiento – isolation y permanencia – durability), STM usa dos: La atomicidad y el aislamiento.

Así, del mismo modo que se definen transacciones de bases de datos, podemos definir transacciones de código de tal manera que sean atomicas (o se ejecuta todo el código o no se ejecuta nada) y aisladas (si se ejecutan varias transacciones de forma concurrente sus efectos serán como si se ejecutaran una tras otra).

Instalación de STM.NET

Para instalar STM.NET se requiere Visual Studio 2008 y no  se soporta la beta de Visual Studio 2010: si instalas STM.NET en una máquina con Visual Studio 2010 vas a tener problemas. Desde la página web de STM.NET puede instalarse una versión modificada del .NET Framework 4.0 (que se instala con la versión 4.0.20506) y el adaptador para Visual Studio 2008, que nos permite crear aplicaciones de consola usando STM.NET. Una vez instalados ambos estamos listos para empezar :)

El primer ejemplo…

Vamos a empezar con un trozo simple de código donde dos threads van a acceder a la misma variable compartida:

static int sharedValue = 0;
static void Main(string[] args)
{
Thread t1 = new Thread(ThreadProc);
Thread t2 = new Thread(ThreadProc);
t1.Start();
t2.Start();

t1.Join();
t2.Join();
Console.WriteLine("sharedValue es {0}", sharedValue);
Console.ReadLine();
}

static void ThreadProc()
{
for (int i = 0; i < 100; i++)
{
sharedValue++;
Thread.Sleep(10);
}
}

Si ejecutais este programa la salida debería ser 200, ya que los dos threads incrementan cada uno 100 veces la variable. Pero como sabemos, threads accediendo a datos compartidos… es sinónimo de problemas. Actualmente para solucionar este problema podríamos usar un lock, pero STM.NET nos da otro mecanismo: crear una transacción para acceder a la variable sharedValue. Actualmente para crear una transacción se usa el método Do, de la clase Atomic y se le pasa un delegate con el método que tiene el código de la transacción.


Así modificamos ThreadProc para que quede:

static void ThreadProc()
{
for (int i = 0; i < 100; i++)
{
Atomic.Do(() => sharedValue++);
Thread.Sleep(10);
}
}

Con esto todo el código que hemos metido dentro del Atomic.Do (en nuestro caso el incremento de la variable) se ejecutará dentro de una transacción, y por el principio de aislamiento, si dos (o más) transacciones se ejecutan a la vez, sus efectos serán los mismos que si se ejecutasen una tras otra. En efecto, ahora al finalizar el programa sharedValue siempre vale 200.


Este es el ejemplo más sencillo: como imitar un lock usando STM.


El segundo ejemplo…


Veamos ahora la propiedad de atomicidad, y como Atomic.Do() no es lo mismo que usar un lock de C#.


Si tenemos el siguiente código:

int _x = 10;    
int _y = 20;
try
{
Atomic.Do(() =>
{
_x++;
_y--;
throw new Exception();
});
}
catch (Exception)
{
Console.WriteLine("_x = {0}, _y = {1}", _x, _y);
}

Cual es el valor de las variables dentro del catch? Pues _x seguirá teniendo el valor de 10 e _y seguirá teniendo el valor de 20. Al lanzarse una excepción dentro de la transacción se realiza un rollback, de forma que las variables recuperan el valor original que tenian antes de entrar en la transacción (principio de atomicidad).


Resumiendo…


Este post ha sido una muy breve introducción a STM.NET. Obviamente se han quedado cosas en el tintero, pero sólo queria mostraros un poco algunas de las ideas que se están cociendo en los DevLabs… El tiempo dirá si estas ideas se terminan consolidando en alguna versión futura del Framework (como Code Contracts) o se quedan en el olvido…


Saludos!


PD: Este es un crosspost desde mi blog de geeks.ms!