You are on page 1of 9

Arquitectura de Aplicaciones para .

NET

Básicamente la Arquitectura se centra en un arquitectura de 3 capas.

1. La capa de presentación que en este caso esta formada por los


Componentes de IU, y los componentes de proceso de IU. Los
componentes de IU pueden ser vistos como la parte con la cual interactuar
el usuario. Las ventanas o páginas web, por decirlo de alguna manera. Los
componentes de proceso de IU podríamos asociarlos a clases de tipo
controladora en UML. Es decir estos encapsulan lógica de navegación y
control de eventos de la interfase.

2. La capa de negocios encapsula lógica de negocios. Los servicios de esta


capa son encapsulados en tres tipos de componentes, dos de los cuales se
tocan en este ejercicio. Las entidades empresariales, que representan
objetos que van a ser manejados o consumidos por toda la aplicación,
estos podrían ser un modelo de objetos, xml, datasets con tipo,
estructuras de datos, que permitan representar objetos que han sido
identificados durante el modelamiento. Los otros tipos de objetos son los
componentes empresariales que contienen lógica de negocio, y en
algunos casos al usar COM+ son los objetos raíz que inician las
transacciones.

3. La capa de acceso a datos que contiene clases que interactúan con la


base de datos. Estas clases surgen como una necesidad de mantener la
cohesión o clases altamente especializadas que ayuden a reducir la
dependencia entre las clases y capas. Aquí podemos encontrar también
una clase con métodos estáticos que permiten uniformizar las operaciones
de acceso a datos a través de un único conjunto de métodos, esta clase es
el SQLHelper que también se usa en este proyecto

LIBNET sigue esta Arquitectura, implementando las tres capas.


1. LIBNET implementa un site de ventas de libros. Esta página representa
la capa de presentación.

Esta es la ventana de la Aplicación. Se ingresa el código de libro y la


cantidad. Cuando se presionar el botón registrar se genera el Pedido. Para
llevar a cabo la generación del Pedido se hace uso de COM+.
Para describir el problema, su diseño y su solución se esta usando UML, en
este caso los diagramas que se usaron fueron, los casos de uso, diagramas
de secuencia, diagramas de componentes, y diagramas de clases por tipos
de componentes según la Arquitectura.
El material de este Hands On contiene un documento en Visio llamado
LIBNET.vsd que contiene el caso de uso a implementar, el diagrama de
secuencia, el bosquejo de la Arquitectura y las clases en cada una de las
capas y componentes, con diagramas UML

Esta es la parte del documento de Visio que muestra la estructura de los


paquetes que se han creado para reflejar la implementación de la
Arquitectura , los casos de uso y los diagramas de secuencia. Aquí
decidimos colocar el diagrama de secuencia en otro paquete para tener
una mejor claridad.
La Arquitectura de LIBNET se muestra en el siguiente gráfico:
LIBNETBusinessLogic contiene la clase de la capa de negocio que
implementan la transacción COM+. En este caso se esta usando COM+
para manejar las transacciones.
- Capa de Negocios, aquí tenemos inicialmente a las entidades
empresariales, que estará implementado en el proyecto
LIBNETBusinessEntity, con el siguiente código:
using System;
namespace LIBNETBusinessEntity
{
public class CPedidoBE
{
private int iIdLibro;
private int iCantidad;

public int IIdLibro


{
get
{
return this.iIdLibro;
}
set
{
this.iIdLibro= value;
}
}
public int ICantidad
{
get
{
return this.iCantidad;
}
set
{
this.iCantidad = value;
}
}
public CPedidoBE()
{
}
public CPedidoBE(int iIdLibro, int iCantidad)
{
this.iCantidad = iCantidad;
this.iIdLibro = iIdLibro;
}

}
}
Como se puede ver LIBNETBusinessEntity solo contiene propiedades y un
constructor, que nos proporciona los objetos que van a contener los datos
que van a pasar a través de las capas. De esta manera todas las capas
conocen la estructura, a través de esta clase
- La lógica de los componentes empresariales según la Arquitectura.
Estará implementada por el componente LIBNETBusinessLogic, y el
objetivo es que contenga la lógica de negocios, y en este caso al usar
COM+ inicien las transacciones
using System;
using LIBNETData;
using LIBNETBusinessEntity;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
namespace LIBNETBusinessLogic
{
[Transaction(TransactionOption.Required)]
[Guid("440FB96E-2EE6-489d-9ED2-F3E2456C0170")]
public class CPedidoBT:ServicedComponent
{
public CPedidoBT()
{
}
[AutoComplete]
public bool RegistrarPedido(CPedidoBE oCPedido)
{
CPedidoD oCPedidoD = new CPedidoD();
if (oCPedidoD.RegistrarPedido(oCPedido))
{
CLibroD oCLibroD = new CLibroD();
oCLibroD.ActualizarStock(oCPedido);
return true;
}
else
{
return false;
}
}

}
}

El atributo AutoComplete en el método permite establecer que este


método RegistrarPedido es transaccional.
public bool RegistrarPedido(CPedidoBE oCPedido)
El método recibe como argumento el obteo ocPedido que es una instancia
de la clase CpedidoBE que ha sido definido dentro de los BusinessEntities
Aquí se llama a la clase de la capa de datos:
CPedidoD oCPedidoD = new CPedidoD();
if (oCPedidoD.RegistrarPedido(oCPedido))
CLibroD oCLibroD = new CLibroD();
oCLibroD.ActualizarStock(oCPedido);
return true;

- La capa de acceso a datos es implementado por el componente


LIBNETSQLData, que contiene dos clases ClibroD y CpedidoD, se han
creado dos clases para aumentar el nivel de reusabilidad de la lógica al
especializar las clases. También tengo que hacer notar el uso de los
métodos estáticos dentro de la clase SqlHelper como una mejor practica
para incrementar la estandarización dentro de nuestros proyectos de
desarrollo a través de todo el equipo de trabajo.
Esta es la definición de la clase de acceso a datos ClibroD
using System;
using Microsoft.ApplicationBlocks.Data;
using LIBNETBusinessEntity;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace LIBNETData
{
[Transaction(TransactionOption.Supported)]
[Guid("440FB96E-2EE6-489d-9ED2-F3E123456170")]

[ConstructionEnabled(Default="server=localhost;database=LIBNET2003;uid=sa;pwd=;")]

public class CLibroD:ServicedComponent


{
private string sCadenaConexion;

protected override void Construct(string s)


{
this.sCadenaConexion = s;
}

[AutoComplete]
public bool ActualizarStock(CPedidoBE oCPedido)
{
int iIdLibro = oCPedido.IIdLibro;
int iCantidad = oCPedido.ICantidad;

try
{
SqlHelper.ExecuteNonQuery(this.sCadenaConexion,
"usp_ActualizarStockLibro",iIdLibro,iCantidad);
return true;
}
catch
{
return false;
}
}

public CLibroD()
{
//
// TODO: Add constructor logic here
//
}
}
}
Notar el uso del Constructor String
[ConstructionEnabled(Default="server=localhost;database=LIBNET2003;ui
d=sa;pwd=;")]

Y como se recupera su valor


private string sCadenaConexion;
protected override void Construct(string s)
{
this.sCadenaConexion = s;
}

El método también se ejecuta dentro de la transacción


[AutoComplete]
public bool ActualizarStock(CPedidoBE oCPedido)
{
int iIdLibro = oCPedido.IIdLibro;
int iCantidad = oCPedido.ICantidad;
try
{
SqlHelper.ExecuteNonQuery(this.sCadenaConexion,
"usp_ActualizarStockLibro",iIdLibro,iCantidad);
return true;
}
catch
{
return false;
}

Para simplificar y uniformizar el acceso a datos se hace uso de la clase


SqlHelper del DataAccessApplicationBlock
SqlHelper.ExecuteNonQuery(this.sCadenaConexion,
"usp_ActualizarStockLibro",iIdLibro,iCantidad);
return true;
La otra clase Cpedido tiene una estructura parecida:
using System;
using Microsoft.ApplicationBlocks.Data;
using LIBNETBusinessEntity;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
namespace LIBNETData
{
[Transaction(TransactionOption.Supported)]
[Guid("440FB96E-2EE6-489d-9ED2-4444456C0170")]

[ConstructionEnabled(Default="server=localhost;database=LIBNET2003;uid=sa;pwd=;")]
public class CPedidoD:ServicedComponent
{
private string sCadenaConexion;
protected override void Construct(string s)
{
this.sCadenaConexion = s;
}
[AutoComplete]
public bool RegistrarPedido(CPedidoBE oCPedido)
{
int iIdLibro = oCPedido.IIdLibro;
int iCantidad = oCPedido.ICantidad;
try
{
SqlHelper.ExecuteNonQuery(this.sCadenaConexion,
"usp_AgregarPedido",iIdLibro,iCantidad);
return true;
}
catch(Exception e)
{
return false;
}
}
public CPedidoD()
}
}

2. Dentro de los archivos de este ejemplo he incluido una versión de


LIBNET que hace uso de un "Factory" para separar independizar la
aplicación del acceso a datos. Esto es algo parecido a lo que se hace en el
PetShop. Un factory se usa cuando por alguna razón los objetos de un lado
no pueden llamar directamente a los objetos del otro lado (en términos
simples esta es una buena descripción). En esta caso, los objetos que no
se pueden llamar directamente son los de la capa de datos. Si se llamaran
directamente la aplicación se haría dependiente de la clase y por lo tanto
de la base de datos. El factory actúa como un creador de objetos,
decidiendo cual es el objeto a crear de acuerdo a parámetros de
configuración. Para que el cliente pueda usar cualquier objeto, estos
objetos implementan una interfaz genérica. De esta forma el factory
retorna esta interfaz, y a través de polimorfismo dinámico, el cliente
obtiene siempre el objeto adecuado con los mismos métodos,
consiguiendo la independencia de las clases de acceso a datos y por lo
tanto de la base de datos.

Esta versión se llama LIBNETPetShop

El proyecto LIBNETIData contiene la definición de las interfaces. Una para


cada clase, Pedido y Libro
ICLibroD.cs
using System;
using LIBNETBusinessEntity;
namespace LIBNETIData
{
public interface ICLibroD
{
bool ActualizarStock(CPedidoBE oCPedido);
}
}
ICPedidoD.cs
using System;
using LIBNETBusinessEntity;
namespace LIBNETIData
{
public interface ICPedidoD
{
bool RegistrarPedido(CPedidoBE oCPedido);
}
}

El proyecto LIBNETIFactoryIData contiene las llamadas a los objetos


adecuados de acuerdo a una configuración en el Web.config
<appSettings>
<add key="WEBData" value="LIBNETSQLData" />
</appSettings>
LIBNETIFactoryIData
LibroFactory.cs
using System;
using System.Reflection;
using LIBNETIData;
namespace LIBNETFactoryIData
{
public class LibroFactory
{
public static ICLibroD Crear()
{
string path=
system.configuration.ConfigurationSettings.AppSettings["WEBData"];
string NombreClase = path + ".CLibroD";
return (ICLibroD) Assembly.Load(path).CreateInstance(NombreClase);
}
}
}
Al hacer uso de las interfaces se hace la llamada al objeto correcto aquí.
public static ICLibroD Crear()
{
string path =
System.Configuration.ConfigurationSettings.AppSettings["WEBData"];
string NombreClase = path + ".CLibroD";
return (ICLibroD) Assembly.Load(path).CreateInstance(NombreClase);
}
Conclusión:
En este laboratorio se trata de mostrar el proceso de desarrollo formal de
software a partir del análisis de requerimientos usando Casos de Uso,
luego el diseño con UML, los diagramas de secuencia. Luego como enlazar
esto con la Arquitectura de Aplicaciones de Microsoft para .NET, y
finalmente como implementar un "patrón" dentro de la aplicación para
independizarla del acceso a datos. En resumen, Una metodología sólida de
desarrollo apoyada por una herramienta Case como Visio Enterprise
Architect, más mejores prácticas (patrones, building blocks, patrones de
Arquitectura), y la implementación usando VS .NET 2003.
Muchos conceptos como Service Oriented Architecture o Model Driven
Architecture me han servido de referencia para llevar a cabo este ejercicio.

You might also like