Aplicaciones Distribuidas 3 CapasParte I / IV
Fecha: 29/Jul/05 (28-07-05)
|
INTRODUCCION:
Las aplicaciones han pasado por un proceso evolutivo enorme. Desde su inicio con las aplicaciones monolíticas donde en una aplicación todo estaba ligado o mezclado por decirlo de alguna manera. Es decir, la interfaces de usuario, la lógica de cómo funcionaba la empresa y el manejo de la información almacenada y recuperada estaban juntas.
Luego la industria ha implementado un nuevo modelo de aplicaciones, las aplicaciones distribuidas cliente/servidor, que se convirtió en el estándar por un tiempo. Pero con la llegada de las aplicaciones web se hacia necesario un nuevo estándar para la operaciones de los sistemas, y es por esto que se ha propuesto el modelo de las aplicaciones en n-capas.
Este modelo por lo general esta basado en un esquema de tres partes: Acceso, Lógica de negocios e interfaces de usuario. Aunque es posible continuar sub dividiendo este modelo en sub capas para una mayor flexibilidad en la distribución en el equipo de desarrollo y durante el mantenimiento. Veamos en que consiste.
Arquitectura de aplicaciones con tres capas
Arquitectura de Aplicaciones en n-capas Se ha convertido en el estándar para el software empresarial. Se caracteriza por la descomposición de las aplicaciones.
• Proporciona una escalabilidad, capacidad de administración y utilización de recursos mejorados.
• Cada capa es un grupo de componentes que realiza una función específica.
• Se puede actualizar una capa sin recompilar otras capas.
Por regla general, La capa de la presentación es una interfaz gráfica que muestra los datos a los usuarios.
La capa de la lógica de negocios es responsable de procesar los datos recuperados y enviarlos a la capa de presentación.
La capa de datos almacena los datos de la aplicación en un almacén persistente, tal como una base de datos relacional o archivos XML.
Se pueden alojar todas las capas en el mismo servidor, pero también es posible alojar cada capa en varios servidores.
Para Ilustrar un poco el concepto de las aplicaciones distribuidas, vamos a crear un pequeño proyecto de 3 capas de venta de películas. En dicha aplicación crearemos:
1- un servicio web como capa de acceso (asumiendo que este sería el modelo utilizado por cada compañía).
2- un servicio web para la lógica de negocios, que en realidad constará de dos, el primero para buscar la información brindada por los proveedores como director, actores, duración, etc. Y otro para conseguir las críticas de algún sitio dedicado a esos fines.
3- Un cliente que compre películas tomando en consideración la información que le brindamos al respecto.
Y para hacerlo más interesante vamos a extender un poco el artículo de nuestro colega Andrés Faya de escribir aplicaciones en distintos lenguajes, para implementar nuestros Web service de igual forma, uno en C# y otro en J# y Nuestra capa de acceso y el cliente van a funcionar bajo el lenguaje de Visual Basic.Net.
Nota: Las aplicaciones distribuidas no necesariamente tienen que estar construidas en base a los web service, estos se utilizan cuando se requiere que la información sea compatible entre plataformas. En caso en que está no sea la prioridad entonces es opcional utilizarla o implementar la distribución de la aplicación por medio de Remoting.Net.
La primera capa que vamos a desarrollar es la capa de acceso a datos. De esta capa cabe mencionar que es recomendable utilizar los Store Procedure en vez de ejecutar las sentencias directas desde el programa.
Se preguntaran por qué? Simple cuando ejecutas las sentencias directas contra la base de datos, toda la información referente a la sentencia viaja a través de la red, consumiendo mas ancho de banda y dejando a merced de algún sniffer la seguridad de nuestra base de datos…piensen como!!!.
La principal ventaja además de reducir los riesgos antes mencionados, es que los procedure son precompilados y funcionan de forma tipados, es decir, que solo reciben los parámetros que tienen preestablecidos y de los tipos específicos para cada caso, sumándole que se ejecutan mucho mas rápido que ejecutando sentencias desde el programa y le dejamos al servidor de base de datos procesar la información creando un mayor balance en la carga de trabajo en nuestra red.
Antes de mostrar el código de la capa de acceso me parece necesario, hacer mención de los mecanismos que nos permiten utilizar los web service que son la base de nuestro ejemplo.
• Lo primero es que necesitamos conocer son UDDI y DISCO que permite a los clientes de los servicios acceder a la funcionalidad que expone un servicio web dándole la ubicación del servicio remoto.
• Luego de conocer la ubicación, los clientes necesitan tener información de cómo interactuar con dichos servicios.
• El formato de los mensajes que intercambiarán el cliente y los servicios web como fundamento de comunicación debe tener un mecanismo de codificación y decodificación.
Para estos fines es indiscutible que el lenguaje a utilizar es el XML que se ha convertido en el estándar de intercambio de información, por permitir la interoperatividad entre plataformas y por usar un sistema de tipo común. Una vez conocidas estas reglas entonces procedemos a codificar.
Código de capa de acceso:
Cabe destacar el uso de la clase Microsoft.ApplicationBlocks.Data versión 1 que nos permite acceso a datos de forma eficaz y rápida...aunque ya existe una segunda versión para los interesados.
Imports System.Data Imports System.Data.SqlClient Imports System.Data.OleDb Imports System.Security Imports System.Configuration Imports Microsoft.ApplicationBlocks.Data Imports System.Web.Services <System.Web.Services.WebService(Namespace:="http:"//tempuri.org/CapaAcceso/Service1")> _ Public Class CapaAcceso Inherits System.Web.Services.WebService #Region " Web Services Designer Generated Code " Public Sub New() MyBase.New() 'This call is required by the Web Services Designer. InitializeComponent() 'Add your own initialization code after the InitializeComponent() call End Sub 'Required by the Web Services Designer Private components As System.ComponentModel.IContainer 'NOTE: The following procedure is required by the Web Services Designer 'It can be modified using the Web Services Designer. 'Do not modify it using the code editor. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() components = New System.ComponentModel.Container End Sub Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) 'CODEGEN: This procedure is required by the Web Services Designer 'Do not modify it using the code editor. If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub #End Region Private sqlconn As String = ("server=(local);database=Peliculas;uid=sql;pwd=mar45245wqek") Private ds As New DataSet Private i As Integer 'Lo primero que debemos saber es que para hacer que una función o procedimiento 'Sea interpretado como un método que puede ser consumido por un cliente web es 'necesario, declararlo con esta finalidad, es decir declararlo como un método web 'Para ello,utilizamos la palabra reservada WebMetohd entre los simbolos de "<>" 'Por lo que quedaría así "< WebMethod() >"
'Lo segundo que debos saber es que para sobre cargar los WebMethod utilizamos 'la propiedad llamada MessageName para que el servicio web distinga estre estas 'funciones o procedimiento. 'Esto no quiere decir que, para llamar dichas funciones usemos el nombre designado 'en el MessageName, se invocan igual que un método sobre cargado en una clase normal.
'Lo siguiente a tomar en cuenta es el nivel de acceso. Pues al igual que en un clase 'cualquiera los niveles de private, public tienen los mismo efectos. Es decir, si desea 'que un método solo sea accesible desde esta clase entonces lo declaras private, pero si 'desea utilizarlo como un servicio web, entonces debe ser public para poder ser accesible 'desde las instancias.
'Sobre cargo la función Query para los diversos caso que pueda necesitar.
'La función del query es para los procedure que retornar valores( Select). <WebMethod(MessageName:="cero")> Public Function Query(ByVal procedure As String) As DataSet ds = SqlHelper.ExecuteDataset(sqlconn, CommandType.StoredProcedure, procedure) Return ds End Function <WebMethod(MessageName:="primero")> Public Function Query(ByVal conexion As String, ByVal procedure As String) As DataSet ds = SqlHelper.ExecuteDataset(conexion, CommandType.StoredProcedure, procedure) Return ds End Function <WebMethod(MessageName:="segundo")> Public Function Query(ByVal conexion As String, ByVal procedure As String, ByVal parametros() As Object) As DataSet ds = SqlHelper.ExecuteDataset(conexion, CommandType.StoredProcedure, procedure, parametros) Return ds End Function <WebMethod(MessageName:="tercero")> Public Function Query(ByVal procedure As String, ByVal parametros() As SqlParameter) As DataSet Try ds = SqlHelper.ExecuteDataset(sqlconn, CommandType.StoredProcedure, procedure, parametros) Return ds Catch ex As SqlException MsgBox(ex.Procedure & ", " & ex.LineNumber & ", " & ex.Message) End Try End Function 'sobre cargo QueryInteger por si necesito que el procesudre me retorne por ejemplo un id. <WebMethod(MessageName:="primer")> Public Function QueryInteger(ByVal procedure As String) As Int32 Try i = SqlHelper.ExecuteScalar(sqlconn, CommandType.StoredProcedure, procedure) Return i Catch ex As Exception Trace.Write(ex.Message) End Try End Function <WebMethod(MessageName:="second")> Public Function QueryInteger(ByVal procedure As String, ByVal parametros() As SqlParameter) As Integer Try i = SqlHelper.ExecuteScalar(sqlconn, CommandType.StoredProcedure, procedure, parametros) Return i Catch ex As Exception Trace.Write(ex.Message) End Try End Function 'Sobre cargo la función NoQuery para los procedure con (Insert, delete, update) <WebMethod(MessageName:="1")> Public Function NoQuery(ByVal procedure As String, ByVal parametros() As SqlParameter) Try SqlHelper.ExecuteNonQuery(sqlconn, CommandType.StoredProcedure, procedure, parametros) Catch ex As Exception Trace.Write(ex.Message) End Try End Function <WebMethod(MessageName:="2")> Public Function NoQuery(ByVal conexion As String, ByVal procedure As String, ByVal parametros() As Object) As Integer Try i = SqlHelper.ExecuteNonQuery(conexion, CommandType.StoredProcedure, procedure, parametros) Return i Catch ex As Exception Trace.Write(ex.Message) End Try End Function <WebMethod(MessageName:="3")> Public Function NoQuery(ByVal conexion As String, ByVal procedure As String) As Integer Try i = SqlHelper.ExecuteNonQuery(conexion, CommandType.StoredProcedure, procedure) Return i Catch ex As Exception Trace.Write(ex.Message) End Try End Function End Class
Esta ha sido la primera parte del artículo, en la siguinte parte vamos a crear los web services. Como habíamos dicho serán creados en lenguajes diferentes, para extender un poco el artículo de nuestro colega Andrés Faya y mostrar la versatilidad y flexibilidad que nos ofrece el dotnet. Me parece que estas caraterísticas, realmente muestran la teoría de otro lenguaje: Compile una vez y uselo siempre aunque sea en otra plataforma,"Cosa que no pasa". Aquí compilamos una vez y podemos usar esas clases en otros lenguajes y al tratarse de un web service en otras plataformas de forma real.