viernes, 30 de noviembre de 2007

Arquitectura ASP Net clásica, modelo de WebForms


Una aplicación web creada con Asp Net de la forma en la que nuestros amigos de Microsoft la han ideado, implica una arquitectura de 2 capas como la siguiente:


En el caso de la capa de aplicación, Asp.Net 2.0 no requiere que se ubique necesariamente código de la lógica de la aplicac. en el archivo code-behind, ya que también se puede agregar el mismo en el código de presentación (.aspx). De todas formas siempre es aconsejable mantener separado las lógicas de aplicación y presentación.

En el caso de la capa de acceso a datos, no es aconsejable acceder desde la capa de aplicación directamente a la BD ( ya sea a través del llamado a procedimientos almacenados ó vía ejecución de comandos SQL) , siempre es mejor crear clases que accedan a la tecnología usada en el acceso a datos; porque ?
Porque con esta decisión de diseño, tendremos las siguientes ventajas:

  • El código de acceso a datos se aísla en una clase separada, por lo cual podemos poner a trabajar a nuestros expertos en BD, mientras los analistas y programadores de lógica de aplicación trabajan en la otra capa.
  • Podemos afinar la perfomance de la BD (tiempos de acceso, pruebas de stress, etc) sin afectar el resto de la aplicación con nuestros cambios.
  • Podemos migrar de tecnología de acceso a datos, por ej.: de SqlServer a Oracle, ó a un ORM (Nhibernate ó Linq, etc); sin afectar las otras capas. (capas como módulos pluggables)

OK, me convencí, voy a generar mis clases de acceso a datos con las operaciones básicas de persistencia (CRUD: Create-Retrieve-Update-Delete), aunque tener esta flexibilidad, no posee ningún costo asociado?
SI lo posee, debido a que Asp.Net está diseñado para trabajar con los controles de las fuentes de datos embebidos en nuestras páginas .aspx, soluciones?:

  • No usar las fuentes de datos (DataSources) de Asp.Net, lo cual significa que no podremos usar “data-binding” en nuestras presentaciones, por lo cual debemos escribir el código que conecta la interfaz de usuario (IU) a las clases de acceso a datos.
  • Usar la nueva fuente de datos de objetos (ObjectDataSource) de Asp.Net 2.0, la cual está diseñada para ligar los controles Asp.Net a clases de acceso a datos, aunque esto agrega una capa de complejidad que en algunos casos tampoco soluciona el problema.
Como es una aplicación web Asp Net??
Los sitios web Asp Net son desarrollados via el uso de los Web Forms (.aspx), éstos brindan la funcionalidad web a los clientes. Un request a un recurso .aspx, como por ej.: http://miWeb.com.ar/CarritoCompras/default.aspx, resulta que sea ejecutado el archivo default.aspx (junto con su archivo code-behind) en el server, luego el resultado será una página html que se enviará al cliente.
En la siguiente imagen podemos ver una pantalla completa de ejemplo de desarrollo con la ide Visual Studio 2005, donde se aprecia una ventana con el "explorador de soluciones" (ver las extensiones .aspx de los WebForms y .aspx.cs del code behind), una ventana "toolbox" donde se ven la gran cantidad de controles Web server de AspNet que pueden agregarse al WebForm; y una página que aparece en modo de diseño, mostrando un control GridView que es usado para mostrar y editar los datos del carrito de compras.

Existen además otros archivos para el diseño de la IU como Web User controls y Master Pages, los cuales son similares a los Web Forms (están compuestos de HTML y código c# ó vb.Net en su code-behind), aunque no pueden ser accedidios de forma directa por los clientes. Estos son usados para componer el contenido de los Web Forms.
Los Web User controls (.ascx) se incluyen en los Web Forms y permiten la reutilización de código en la capa de presentación.
Los Master Pages (.master) son templates que pueden ser aplicados a gran número de Web Forms , para asegurar consistencia visual y funcionalidad a través de varias páginas del sitio. Normalmente usados para encabezado y pie de nuestro sitio, mapa del sitio, columnas con menúes.

Controles del lado del servidor, existen 2 categorías:
  • Html, permiten acceder a los elementos HTML de la página a través del código (en el code-behind). Se transforma un control Html (Button, TextBox, RadioButton,...) a un Html server agregandole el atributo “runat=server”. La mayoría de los controles Html están duplicados con mayor funcionalidad en los controles Web server, aunque a veces ud. deberá usarlos.
  • Web server, son clases .NET compiladas que, al ser ejecutadas, generan código Html como salida, eventualmente pueden incluír scripts del lado del cliente.
    Pueden ser usados en los Web Forms en forma directa ó a través de la creación de Web User controls. Estos incluyen controles simples como TextBox ó Button, y otros más complejos como el GridView (el viejo DataGrid) que permite mostrar datos de la BD en forma de tabla con manejo de muchas propiedades de diseño y eventos.
A continuación les muestro algunas pantallas que fueron obtenidas del VS 2005 para ejemplificar características importantes que hacen al desarrollo de páginas Asp Net (WebForms)
El VS me permite visualizar las páginas en 2 modos: el de diseño


que me permite visualizar como se verá la página en el Browser, en el ejemplo se ve "deshabilitado" el acceso a la cabecera y pie del sitio que son parte del master page al cual pertenece esta página.
Y el modo de "código fuente":


Aquí se puede editar el código html y los controles Web de asp net que han sido agregados en modo de diseño (encapsulados en los tags ).





Por último un ejemplo del code behind (.aspx.cs) de esta página, donde normalmente generamos nuestro código de manejo de eventos de la página y de los controles :



Con este post he intentado demostrar a aquellos que no han programado con AspNet, las principales características de la arquitectura clásica de desarrollo web, así el lector podrá comprender mejor las diferencias existentes contra la nueva propuesta del MVC para AspNet posteada anteriormente.

martes, 27 de noviembre de 2007

EL futuro MVC de Asp Net

Luego de haber leído los artículos de Scott Guthrie y Dino Esposito voy a realizar un resúmen de la propuesta MVC para ASP NET.

Para crear una aplicación de este tipo con VS, elegimos un nuevo proyecto de tipo “ASP.NET MVC Web Application”, de esta forma se creará una nueva solución y se añadirán dos proyectos: un proyecto web en el que implementaremos nuestra aplicación y un proyecto de testing que usaremos para escribir test unitarios (TDD...)
La estructura por defecto de un ASP.NET MVC tiene 3 directorios:

  • /Controllers
  • /Models
  • /Views
Por lo cual, crear las clases controladoras en el directorio /Controllers, las de modelo de datos en /Models, y las vistas en el directorio /Views.
Cabe aclarar que el Framework no te obliga a usar esta estructura, pero el template usa este patrón. Consultando a Scott sobre el uso de ensamblados (dll) para la controladora y el modelo (mis capas de negocio y acceso a datos), dijo no existir problemas en agregar las referencias a los mismos y usarlos en el MVC en vez de las carpetas creadas por default; si no fuera así no podríamos usar nuestras controladoras y modelos de un proyecto a otro, debiendo reescribir código en cada solución.


Por defecto los proyectos MVC tienen unas reglas de enrutado de urls preconfiguradas, de esta forma podemos empezar a escribir el código usando un conjunto de convenciones para nombrar las urls que van a usarse en nuestra aplicación.

Las Controladoras...
El convenio por defecto es mapear el path de la url de una petición HTTP (por ejemplo: /Products/) a una clase cuyo nombre siga el patrón UrlPathController (por ejemplo: una url que termine con /Products/ se mapeará a la clase ProductsController).
Por lo tanto si agregamos la clase “ProductsController” (que herede de System.Web.MVC.Controller) a nuestro proyecto, el framework ASP.NET MVC la usará para procesar todas las peticiones cuya url contenga la cadena “/Products”. Es decir, será llamada para procesar las urls “/Products/Categories”, “/Products/List/Beverages”, “/Products/Detail/3″ (donde 3 será el id. del producto), etc.



El framework MVC nos permite definir “métodos de acción” en nuestro controladora, y la clase base Controller invocará el método apropiado, así que cuando recibimos una petición de la forma "/Products/Categories”, la regla de enrutado tratará la parte “Categories” como el nombre de la acción, y se invocará el método Categories() para procesar la petición, si recibimos una petición a la url "/Products/Detail/5", la regla tomará el nombre “Detail” como el nombre de la acción y se invocará al método Detail(), etc.

Como accedemos a los parámetros de las urls?
La clase base Controller expone un conjunto de objetos Request y Response que podemos usar. Estos objetos tienen la misma estructura que los objetos HttpRequest/HttpResponse a los que estamos acostumbrados en ASP.NET, la diferencia es que estos objetos están basados en interfaces en lugar de en clases selladas (sealed) (MVC trae las interfaces System.Web.IHttpRequest y System.Web.IHttpResponse), esto nos da la posibilidad de poder implementarlos como queramos, uno de sus usos será crear test unitarios para clases controlador.

En la acción List , aparece un parámetro de la categoría, que es parte de la URL, y un índice de página opcional (implementaremos paginado en el servidor y usaremos ese valor para indicar qué página de categoría mostrar en la petición).
Los parámetros opcionales se manejan usando tipos de datos nullables en los métodos de acción de las controladoras. El parámetro “int?” de nuestra acción List es nullable.



Construyendo las clases del Modelo
Para crear nuestras clases que accedan a la información de la BD, Scott lo realiza mediante "Linq to Sql" (ORM), el cual me permite obtener como resultados listas de objetos. También podría usar NHibernate o cualquier otro tipo de ORM, ó Ado.Net (no recomendado, ya que debo mapear registros a listas de objetos) para construir mis clases del Modelo.



Volviendo a nuestra controladora, vemos el uso que se hace del modelo creando un objeto de tipo "NorthwindDataContext" (clase creada con la utilidad de Linq), y llamando a sus métodos, como por ej.: en el método "Detail(int id)" donde llamamos a "northwind.GetProductById(id)".


Y la Vista??
Cuando implementamos los tres métodos de acción del controlador en la clase ProductsController, usamos los parámetros de la URL para obtener los objetos adecuados de nuestra BD, para luego seleccionar una vista adecuada para generar una resputesta HTML. Usaremos uno de los métodos RenderView() de la clase base Controller para espcificar la vista que queramos usar, así como explicitamente le pasaremos los datos específicos que queremos que la vista use para renderizar la respuesta. Por ej: RenderView("Detail", product), donde product es el objeto de tipo Product obtenido del llamado al Modelo.
Para crear la vista a la cual hacemos referencia en el ej. ("Detail"), podemos usar cualquier motor de templates para ayudarnos a generar la interfaz de usuario (incluyendo motores como NVelocity, Brail - y cualquiera que escribamos ). Por defecto ASP.NET MVC usa las páginas ASP.NET (.aspx), Master Pages (.master) y UserControls (.ascx).


Conclusiones
Este framework no reemplaza el modelo basado en WebForms de Asp.Net, sólo nos agrega la posibilidad de crear nuestras aplicaciones bajo este paradigma, aplicando a la perfección este viejo patrón de arquitectura (MVC).


En el post de Dino, se le pregunta a los lectores si han escuchado hablar de REST (Representational State Transfer) , el cual es otro patrón de arquitectura que encaja perfectamente en el proceso del MVC AspNet, que describimos anteriormente.
REST define cómo los recursos de la red deberían ser definidos y direccionados con el objetivo de: obtener menores tiempos de respuesta y separar las responsab. entre front-end y back-end. Se basa en los sig. principios:

  • Una aplicación expresa su estado e implementa su funcionalidad actuando sobre recursos lógicos.
  • Cada recurso es direccionado usando una URL específica.
  • Todas las ventajas que poseen esos recursos direccionables se agrupan en un juego de operaciones.

Por lo tanto el framework MVC de AspNet usa un modelo REST que compite con el modelo clásico de "postback" de AspNet.



Cada página se separa en 2 componentes (controladora y vista) que operan sobre el mismo modelo de datos; esto es opuesto al clásico modelo "code-behind" donde no existen barreras que nos fuercen a separar las responsab. entre controladoras y vistas.


Aunque manteniendo las clases "code-behind" (nuestras aspx.cs) lo más ligeras que sea posible y diseñando la capa de negocios de forma apropiada (ver ejemplo de capa de negocio), un buen desarrollador logra separar estas responsabilidades manteniendo la lógica de la aplicación en la capa que corresponda.

Bueno, en este post se ha intentado aclarar un poco de que trata un framework MVC, tomándolo como una opción más a la hora de desarrollar software para Web. Cualquier extensión al tema leer los posts de Scott y Dino que están referenciados al principio.

viernes, 23 de noviembre de 2007

Introducción a los frameworks MVC

Ya hemos visto una arquitectura de 3 capas lógicas, ahora investiguemos como desarrollar un MVC (model-view-controller) , que fue explicado muy someramente en este post.












Sin lugar a dudas estos frameworks han ganado terreno en el desarrollo de sitios Web, donde RubyOnRails ha sido la inspiración de otros desarrolladores de frameworks de este tipo. En el caso del mundo .NET, la creación de MonoRail sumó muchos adeptos en la comunidad de desarrolladores y todos comenzamos a mirar de reojo para cuando Microsoft sumaría una propuesta de desarrollo que rompiera con el modelo basado en WebForms (.aspx), ó al menos agregara la posibilidad del MVC.

El modelo actual de MS impone que los request de los clientes son solicitudes a páginas (WebForms) aspx que contienen controles Web ASP.Net, los cuales disparan eventos a una controladora de esa página. Esta controladora es normalmente código C# ó VB.Net agregado al WebForm, y conocido como "code behind" (aspx.cs ó aspx.vb). En este tipo de arquitectura el cliente hace Request a objetos de la capa de presentación (WebForms aspx), que luego llaman a su objeto controlador para pedirle funciones, estas luego harán solicitudes sobre el Modelo (mi acceso a datos en el 3 capas lógicas).

En el caso de un MVC, el Request se realiza a un objeto de tipo Controlador que crea una presentación como Response a esa solicitud. Si se fijan en el diagrama MVC dice que la "Controladora selecciona la Vista que irá como respuesta".

Pues bien, Microsoft responde a la comunidad de desarrolladores .NET con la siguiente sorpresa (quizás no tanto...) el dia 13/11/2007 : The Asp.Net MVC framework. Ver el extenso post que publicó el gran Scott Guthrie (jefe de proyectos de MS: IIS, ASP.NET, Atlas, CLR, Compact Framework, Windows Forms, etc, etc.).
Allí se aclara que será agregado al VS 2008 como una ventaja opcional, a través de un template para la creación de proyectos de tipo MVC, también que este modelo fuerza a una limpia separación de responsabilidades de la aplicación, que permite realizar testeos de los componentes soportando TDD (desarrollo manejado por el testing), y que provee mayor control sobre las URLs que se publican en su aplicación, y mayor control sobre el código HTML que se emite desde ellas.

Esta es una vista de como las URLs se mapean a clases Controladoras:

En el post de Scott, se aclara que en la mayoría de los frameworks Web (ASP Net WebForms,PHP,JSP,...) las URLs se mapean con archivos template almacenados en el disco del servidor web, por ej: un url "/Productos.aspx" tiene un archivo subyacente Productos.aspx en disco que maneja el procesamiento de la misma.

En cambio, en los frameworks MVC las URLs se mapean directamente a clases, estas son denominadas "Controladoras" y son las que procesan los Request entrantes, manejando las entradas del usuario, sus interacciones y ejecutando la lógica apropiada para el proceso. Una clase controladora llama a una vista, la cual genera la salida HTML que se enviará como Response.
En prox. posts entraré en más detalles sobre este ASP.Net MVC y en el modelo de WebForms.

martes, 20 de noviembre de 2007

Arquitectura del software?


Muchas veces nos hablan de la arquitectura en el desarrollo de sistemas. Palabrita de moda quizás...; ingenieros, analistas y programadores que se hacen llamar "Arquitectos de software" como si de un título se tratase. Hasta yo la he puesto como título en mi Blog, entonces, cual es el significado de la Arquitectura en el desarrollo de un sistema?, tratemos de averiguarlo.

En setiembre de este año se realizaron las 36 jornadas de la Jaiio en mi ciudad (Mar del Plata), y al ver el temario de los seminarios, me informo de un curso especial de 8 hs. seguidas, llamado "Introducción a la arquitectura del software", dictado por el Gerente de relac. académicas de Microsoft y profesor de la UBA Pablo Michelis. Por supuesto para entender mejor este concepto y para agregar valor a mis clases me inscribí; esto intenta ser un breve resúmen del mismo.

Comencemos por definir "Arquitectura del soft":
"Estructura de sistemas o sistema de estructuras que consisten en elementos, sus propiedades externamente visibles y la relación entre ellos"
"Propiedades externamente visibles: qué es lo que debe saber/suponer un componente sobre otro?"
Por último :
"
Toda la arquitectura es diseño, pero no todo el diseño es arquitectura. La arquitectura representa las decisiones de diseño significativas que le dan forma a un sistema, donde lo significativo puede ser medido por el costo del cambio". (Grady Booch)

Creo que es la más simple y directa definición de arquitectura.

Basándonos en esta última definición podemos suponer que lo que distingue a la arquitectura de otro tipo de diseño es la significancia expresada en la dificultad ó costo del cambio.
La arquitectura del soft mantiene unidas las nociones de : diseño, estructura, estilo, racionalidad, proceso y costo.
Ahora bien, como podemos evaluar la calidad de una determinada arquitectura para nuestra solución de software? , quizás una buena arquitectura sea aquella en la que las decisiones de diseño significativas se lograron minimizar, evitando riesgos de cambio futuros. De esta forma estaríamos libres de cambiar varios aspectos del sistema sin el miedo a que tales cambios produzcan cascada de errores y cambios en el diseño que nos llevarían a altos costos de mantenimiento. Una buena arquitectura debe ser sustentable.

Como se relaciona esta visión de la arquitectura con la estructura del sistema?, pues construyamos componentes, clases, paquetes, ensamblados, etc. que sean altamente cohesivos y con bajo acoplamiento (nuestro ying y yang recuerdan?).
En una arquitectura con bajo acoplamiento, donde los puntos de variación futuras estén bien encapsulados, los efectos del cambio estarán bien aislados y el costo será relativamente bajo.
Por esto es que a nivel de arquitectura hablamos de los patrones de diseño, que nos permiten el desarrollo de mejores arquitecturas de software como por ejemplo la 3 capas explicada y ejemplificada en previos posts.

lunes, 19 de noviembre de 2007

Desarrollar en 3 capas con .NET (parte 2) - La controladora y la presentación

Antes de mostrar el manejo de la capa de negocio, les aclaro el concepto de Viatico:
"es una retribución diaria que cobra un empleado cuando la empresa lo envía a realizar alguna tarea fuera de su ámbito normal de trabajo (normalmente a otra ciudad), este importe diario depende de la categoría del mismo. A esto se le suman todos los gastos extras que surjan por movilidad, inscripción a cursos, etc. Normalmente se genera una Solicitud que , en caso de ser aprobada por un superior genera el Viático correspondiente." (los sustantivos marcados en negrita corresponden a algunos de los objetos de negocio de nuestro sistema).

Aclarado este punto importante para poder entender mínimamente el objetivo del sistema, a continuación veremos como desarrollar nuestra capa de negocio.

La capa de negocio (ó dominio del problema) de nuestro sistema, estará compuesta de todos los procesos que fueron analizados como casos de uso, por lo que es común denominar a estas clases : controladora del caso de uso XX.

Capa de negocio (componente ViaticoProcesos)

En mi caso de ejemplo tengo una clase CSolicitud que posee la responsabilidad de controlar todos los procesos inherentes al manejo de Solicitudes de viáticos.
Si quisiéramos darle más flexibilidad (y en consecuencia mayor reutilización futura) al sistema, deberíamos desarrollar una interfaz que agrupe los métodos comunes a todos los posibles sistemas de Viáticos (IViaticoSolicitud) .
Logrando cierta abstracción defino los contratos de mi interfaz:

public interface IViaticoSolicitud
{
void CrearSolicitud(Solicitud nueva);
Viatico AutorizarSolicitud(Solicitud s);
void ImprimirSolicitud(Solicitud s);
List BuscarSolicitud(Solicitante s);
List
BuscarSolicitud(Solicitante s, DateTime Desde);
List BuscarSolicitud(Solicitante s, DateTime Desde, Boolean Aprobadas);
Solicitud BuscarSolicitud(int id);
}

Asi que entonces mi clase CSolicitud implementará mi IViaticoSolicitud:


public class CSolicitud:IViaticoSolicitud
{
// Declaro los DAOs con los que va a trabajar mi controladora

ISolicitudDao solicitudDao;

IViaticoDao viaticoDao;

IEmpleadoDao empleadoDao;
IMovilidadDao movilidadDao;


public CSolicitud()

{ // Creo la fabrica y los DAOs que usaré
NHibDAOFabrica fabricaDAO = new NHibDAOFabrica();

this.solicitudDao = fabricaDAO.GetSolicitudDao();

this.viaticoDao = fabricaDAO.GetViaticoDao();

this.empleadoDao=fabricaDAO.GetEmpleadoDao();

this.movilidadDao = fabricaDAO.GetMovilidadDao();

}


#region IViaticoSolicitud Members


public void CrearSolicitud(Solicitud nueva)

{
if (nueva.Solicitante != null)
{ try { this.solicitudDao.Save(nueva); }
catch { thro
w; }
}
}

public Viatico AutorizarSolicitud(Solicitud s)

{
try
{ // Marco como aprobada la Solicitud
s.Aprobada = true;
// Creo Viatico basado en la Solicitud aprobada
Viatico v = new Viatico();
v.Estado = Viatico.estado_viatico.Creado;
v.Solicitud = s;

v.Numero = this.viaticoDao.DarUltimoNro()+1; // Verificar concurrencia...
// Persisto cambios en Solicitud y Grabo nuevo viatico
this.solicitudDao.SaveOrUpdate(s);

this.viaticoDao.Save(v);

return v;
}
catch { throw ; }
}

public void ImprimirSolicitud(Solicitud s)
{
throw new Exception("The method or operation is not implemented."); }

public List BuscarSolicitud(Solicitante s)
{
try

{
List lista = this.solicitudDao.DarSolicitudesXSolicitante(s,null,null);

return lista;
}
catch { throw ; }

}


public List BuscarSolicitud(Solicitante s, DateTime Desde)
{
try
{
List lista = this.solicitudDao.DarSolicitudesXSolicitante(s, Desde, null);
return lista;
}
catch { throw ; }

}


// etc, etc ..............


#endregion

}

Como verán muchos de los métodos solicitan objetos a la capa de acceso a datos (clases DAO), por lo que termina siendo un llama
do a un método similar en el DAO. Aquí es donde mis alumnos dicen " porqué debemos hacer las cosas por duplicado?, y si llamamos desde la capa de presentación al método del DAO directamente ? ".
OK, el tema es que la Controladora posee métodos como
AutorizarSolicitud(Solicitud s), donde debemos desarrollar código que sólo es inherente al proceso de negocio y además trabajar en una transacción con varios objetos DAO.
En este ejemplo se cambia un atributo del objeto Solicitud, se crea un objeto Viatico, se pide un nro. de viático a un método estático de Viatico, y se persisten ambos objetos, vía llamado a los métodos de sus DAOs.

Capa de presentación Web (componente ViaticoWeb)

Por último, veamos un ejemplo de mi Capa de presentación Web, que permite la autorización de determinada solicitud de viático.
La página web muestra una lista de las solicitudes a autorizar por este usuario (jefe).
Selecciona una, y pulsa el botón "Autorizar".



Al pulsar este botón lo captura el evento "click" del mismo y este es el código:

protected void ButtonAutorizar_Click(object sender, EventArgs e)
{
Solicitud elegida=(Solicitud)Session["SolicitudBuscada"];
if (elegida!= null)
{
// creo controladora de Proceso de Solicitudes
CSolicitud cSolicitud = new CSolicitud();
try
{
Viatico v=cSolicitud.AutorizarSolicitud(elegida);
this.CargarGrid((Usuario)Session["Usuario"]);
this.LabelError.Text = "Viatico"+v.Numero.ToString()+" CREADO";
}
catch
{
Exception ex = new Exception();
this.LabelError.Text = ex.Message;
}
Response.Redirect("~/Admin/Autorizar.aspx");
}
else
this.LabelError.Text = "Seleccione una Solicitud para Autorizar...";
}

Como ven , se crea un objeto de tipo CSolicitud y se llama a su método AutorizarSolicitud pasándole como parámetro la solicitud seleccionada por el usuario. Cualquier error en el proceso llamado será capturado (catch), mostrándose el mensaje de error pertinente.

Capa de Objetos de negocio (componente ViaticoBO)

Mis objetos de negocio son clases independientes de la tecnología que se use para persistencia.
Ejemplo: mi BO Solicitud.

public class Solicitud
{
public Solicitud()
{ }

int id;

public int Id
{
get { return id; }
set { id = value; }
}
Solicitante solicitante;

public Solicitante Solicitante
{
get { return solicitante; }
set { solicitante = value; }
}
System.DateTime fecha_soli;

public System.DateTime Fecha_soli
{
get { return fecha_soli; }
set { fecha_soli = value; }
}
string motivo;

public string Motivo
{
get { return motivo; }
set { motivo = value; }
}

int numero;

public int Numero
{
get { return numero; }
set { numero = value; }
}
string origen;

public string Origen
{
get { return origen; }
set { origen = value; }
}
string destino;

public string Destino
{
get { return destino; }
set { destino = value; }
}
System.DateTime desde;

public System.DateTime Desde
{
get { return desde; }
set { desde = value; }
}
System.DateTime hasta;

public System.DateTime Hasta
{
get { return hasta; }
set { hasta = value; }
}
Movilidad ida;

public Movilidad Ida
{
get { return ida; }
set { ida = value; }
}
Movilidad vuelta;

public Movilidad Vuelta
{
get { return vuelta; }
set { vuelta = value; }
}

Boolean aprobada;

public Boolean Aprobada
{
get { return aprobada; }
set { aprobada = value; }
}

}

En este componente también poseo los archivos de mapeo XML que necesita NHibernate (1 por clase BO), ya que recomiendan que estén en la misma .dll que las clases que mapean.

Bueno, hasta aquí, esta breve explicación de mi desarrollo con la arquitectura 3 capas usando .NET y NHibernate; no quise profundizar en el uso de ninguna herramienta, sólo mostrar ejemplos del desarrollo a nivel de arquitectura y componentes de soft.
Quedo a las órdenes de cualquiera que desee aportar comentarios sobre mejoras, experiencias, ó preguntas sobre la forma de trabajo; que quizás no hayan quedado del todo claras en este post.


jueves, 15 de noviembre de 2007

Desarrollar en 3 capas con .NET y NHibernate - Parte 1 (Acceso a datos)

Luego de haber posteado que es el diseño en 3 capas, y que es un ORM con ejemplos de NHibernate, estamos en condiciones de comprender el desarrollo de software mediante esta arquitectura con el framework .NET.
Echemos un vistazo a este diagrama de componentes que aplica esta arquitectura de 3 capas (para el desarrollo de un sistema de viáticos):


















Podemos ver que además de las capas de presentación, procesos del negocio y acceso a datos, tenemos los objetos de negocio aparte como si de otra capa se tratase. Aunque en la realidad debería estar en la capa del medio, esto presenta problemas en la capa de acceso a datos que pasaría a desconocer los objetos con los que debe trabajar NHibernate en nuestras clases DAO. Para comprender claramente de que estoy hablando debemos ver las clases que se encuentran en cada componente de software.

Empezando por el acceso a datos:




















NHibernateCore

Aqui estan : una interfaz para los DAO (data access object) genérica (IDAO), una clase abstracta que implementa IDAO (NHibDAOAbstracto), y manejo de sesiones y transacciones de NHibernate. Su contenido responde al excelente trabajo de Billy McCafferty: NHibernate best practices with ASP.Net, cuya lectura recomiendo, antes de comenzar a desarrollar una capa de acceso a datos.

Por ej. IDAO:

public interface IDAO // maneja Generics de Net 2.0
{
T GetById(IdT id, bool shouldLock);
List GetAll();
List GetByExample(T exampleInstance, params string[] propertiesToExclude);
T GetUniqueByExample(T exampleInstance, params string[] propertiesToExclude);
List Find(string consulta);
IList FindRetLista(string consulta);
T Save(T entity);
T SaveOrUpdate(T entity);
void Delete(T entity);
void CommitChanges();
}

  • ViaticoDAO
  • Aquí se encuentran : la fábrica de DAOs, y los DAO de cada objeto de negocio.
    Por ej. la clase SolicitudDAO :
    public class SolicitudDAO : NHibDAOAbstracto, ISolicitudDao
    // Hereda del DAO abstracto definido en NHibernateCore e implementa ISolicitudDao
    // para no hacer uso directo del DAO abstracto
    {

    public List DarSolicitudesXSolicitante(Solicitante s, Nullable Desde, Nullable Aprobadas)
    {
    string criterios = "FROM Solicitud a WHERE a.Solicitante.ID = " + s.ID.ToString();

    if (Desde != null)
    criterios += " and Fecha_soli >=" + ((DateTime)Desde.Value).ToShortDateString();
    if (Aprobadas != null)
    {
    if (Aprobadas == true)
    criterios += " and Aprobada=1";
    else
    criterios += " and Aprobada=0";
    }

    IDaoFabrica daoFabrica = new DAOFabrica();
    ISolicitudDao soliDao = daoFabrica.GetSolicitudDao();

    List solicitudes;
    solicitudes = soliDao.Find(criterios);
    return solicitudes;
    }

    public Solicitud DarSolicitudXid(int id)
    {
    IDaoFabrica daoFabrica = new DAOFabrica();
    ISolicitudDao soliDao = daoFabrica.GetSolicitudDao();

    Solicitud s = soliDao.GetById(id, false);
    return s;
    }
    }


    ISolicitudDao:

    public interface ISolicitudDao : IDAO
    {
    List DarSolicitudesXSolicitante(Solicitante s, Nullable Desde, Nullable Aprobadas);

    Solicitud DarSolicitudXid(int id);
    }

    Por último un ejemplo de DAOFabrica:

    public class DAOFabrica : IDaoFabrica
    {
    public IEmpleadoDao GetEmpleadoDao()
    {
    return new EmpleadoDAO();
    }


    public ICategoriaDao GetCategoriaDao()
    {
    return new CategoriaDAO();
    }


    public ISolicitudDao GetSolicitudDao()
    {
    return new SolicitudDAO();
    }

    ...
    }

    Lo destacable en esta capa de acceso a datos es su independencia del motor de NHibernate, gracias al uso de la Fábrica de DAOs. Por ej. si quisiera reemplazar el NHibernate por Linq for Sql (del Net 3.0), cambiaría en mis DAOs la herencia de la clase abstracta que implementa los métodos contra el motor de acceso a datos:
    public class SolicitudDAO : NHibDAOAbstracto, ISolicitudDao por
    public class SolicitudDAO : LinqDAOAbstracto, ISolicitudDao

    Por supuesto deberé desarrollar mi clase LinqDAOAbstracto para que implemente los métodos de la interfaz IDAO.

    En parte 2 veremos la capa de negocio (procesos y reglas; ó controladoras de los casos de uso) y ejemplos de los objetos de negocio, cuyas clases están implementadas en su propio componente.