ejemplo practico de aplicacion cliente servidor

Upload: gaby-capelo-vazquez

Post on 07-Jul-2015

71 views

Category:

Documents


0 download

TRANSCRIPT

EJEMPLO PRACTICO DE APLICACIN CLIENTE SERVIDORLa tecnologa de diseo de aplicaciones segn el modelo cliente-servidor es la ms utilizada en el desarrollo de programas flexibles, seguros y mantenibles. Puede llevarse a cabo segn diferentes estructuras, que veremos paso a paso en este ejemplo.

ORGANIZACIN DEL CDIGO La organizacin del cdigo, su estructuracin segn el modelo de orientacin al objeto, es fundamental si queremos conectar los diferentes componentes de forma rpida y fiable. Por lo tanto, el diseo de los elementos del proyecto (la solucin en el caso de .NET) es algo DETERMINANTE. 1) La clase de acceso a los datos En una aplicacin de este tipo siempre tendremos una clase principal que ser la encargada de proveer todos los servicios de acceso a los datos. En ningn otro sitio del programa se debe acceder directamente a las bases de datos. Este componente encapsula, asla los datos del resto de la aplicacin. 2) Un programa de pruebas (en modo consola o en modo visual) que permita verificar el funcionamiento de la clase de acceso a los datos. En este programa, mediante un men, programaremos las funciones que nos permitan llamar a cada uno de los mtodos y propiedades de la clase de acceso a datos. Adems de un buen banco de pruebas, esta aplicacin constituye un elemento fundamental en la documentacin de la misma, permite ver con claridad la forma de utilizar cada uno de sus elementos. Adems, cuando se trabaja en grupo, el encargado de cada componente debe generar un proyecto de pruebas sencillo que le permita depurarlo y ponerlo en marcha antes de juntarlo con el resto de mdulos, y servir de clarificacin para el resto de compaeros de trabajo. 3) Clases satlite de la aplicacin Una aplicacin de acceso a datos puede trabajar directamente con objetos de tipo DataSet, pero en muchas ocasiones es preferible el diseo de clases especficas para las entidades que viajan entre cliente y servidor. Estas clases suelen coincidir con las entidades del modelo de la base de datos. Las relaciones 1 N de la base de datos se implementan habitualmente como ArrayList dentro de la clase. Generalmente, queda mucho mejor documentado y claro un esquema que trabaje con clases en lugar de un esquema que trabaje con DataSets. Si trabajamos con DataSets, para cada caso deberemos documentar el modelo entidad/relacin del mismo. 4) El prototipo visual Si la aplicacin va a realizarse en el entorno de Aplicaciones para Windows, debemos realizar un prototipo funcional, que permita ver cmo quedar el diseo final, sin implementar las funciones de acceso a datos. nicamente ha de permitir la navegacin sobre los diferentes escenarios que tendremos. Segn el tipo de aplicacin, puede ser necesario el desarrollo de varios prototipos, dirigidos a diferentes perfiles de usuario. En ningn caso se debe mezclar este prototipo con la gestin de los datos. La gestin de los datos es nica, y los prototipos utilizan aquellas partes de la clase de gestin que sea necesario.

5) Los datos globales de la aplicacin cliente En la aplicacin cliente tendremos una serie de datos globales que van a ser utilizados en todo el programa. La conexin con la clase de acceso a datos es un ejemplo. Dado que programamos en un entorno de orientacin al objeto, NO TENEMOS VARIABLES GLOBALES. Con este modelo, la clase de inicio debera tener toda la informacin global, y pasarla a cada uno de los elementos que se van activando. Para evitar esta situacin, construiremos una clase ESTATICA en el proyecto, donde almacenaremos aquellos datos que deban ser utilizados globalmente. 6) La estructura de proyectos Para separar correctamente las distintas partes del proyecto, en nuestra solucin deberemos tener como mnimo los siguientes elementos: - Una biblioteca de clases. Contendr la clase de acceso a datos y las clases satlite (si las hay). - Un proyecto de pruebas. Permitir probar cada mtodo/propiedad de la clase de datos (no importa si es en modo consola). - Un proyecto cliente. Ser la aplicacin que utilizarn los usuarios para trabajar (visual). Si la aplicacin es local, con esto ser suficiente. Si la aplicacin trabaja con remoting, deberemos implementar adems un nuevo proyecto que contenga el programa de activacin del objeto remoto. Ser el programa servidor. Si la aplicacin trabaja con Web services, deberemos implementar un proyecto Web Service, que incruste un objeto del tipo de acceso a datos, y que publique los mtodos web correspondientes. Estos mtodos web deberan estar diseados polimrficamente iguales (i.e. con el mismo nombre y parmetros) que los de la clase de acceso a datos. Si la aplicacin es una pgina web, tendremos un proyecto Web, que incrustar un objeto del tipo de acceso a datos, y que implementar toda la funcionalidad. Este ser realmente el proyecto cliente, ya que en las mquinas cliente slo tendremos el recurso del navegador.

En este tutorial veremos paso a paso la generacin de cada uno de estos componentes, con las consideraciones de diseo importantes a tener en cuenta.

GENERACIN DE LA SOLUCIN Para generar la solucin, daremos de alta inicialmente el proyecto de biblioteca de clases. Podra ser otro, pero este ser el ms importante, es el mdulo que hay que disear sea cual sea la opcin final escogida.

Es MUY IMPORTANTE crear la solucin en una carpeta CONOCIDA. El proyecto inicial NO DEBE ESTAR EN LA CARPETA DE LA SOLUCION. Debe estar en una carpeta independiente, dentro de la carpeta de la solucin. Para ello, marcaremos [Create directory for Solution], y daremos NOMBRES SIGNIFICATIVOS tanto a la solucin como al proyecto. Ahora daremos de alta el programa de pruebas, que en este caso ser una aplicacin visual de Windows.

Mediante el botn derecho encima de la solucin, escogeremos [Add] [New Project]. Este es el mecanismo que deberemos seguir para aadir los dems proyectos a la solucin global. Se puede hacer tambin a travs del men principal de .NET, pero lo ms rpido e intuitivo es ir por aqu.

El programa de pruebas nos servir para verificar inicialmente que no hay errores sintcticos, cambiar el nombre de todos aquellos elementos que lo hayan tomado por defecto, compilar, y obtener un programa vaco, PERO CORRECTO, que puede compilar y ejecutar. Si pretendemos que al poner el punto tras un objeto de una clase aparezcan sus mtodos y propiedades en el desplegable, debemos generar una estructura compilable antes.

ADECENTAREMOS todos los nombres por defecto que aparezcan en los proyectos. Hay que tener en cuenta que SIEMPRE que aadimos un componente, antes de utilizarlo, hay que ponerle un nombre correcto. Una vez empecemos a programar, cambiarlo se ir haciendo cada vez ms complicado. Esta es la estructura de la solucin que tenemos hasta ahora: Proyecto GestionLib, la biblioteca de acceso a datos. Proyecto Pruebas, para realizar las pruebas.

Gestion.csusing System; namespace GestionLib { public class Gestion { public Gestion() { } // Meotodo de pruebas, para verificar que las llamadas se // hacen correctamente public int MetodoDePruebas (int x, int y) { return x+y; } } }

MainFrm.cs

El formulario inicial de pruebas tendr un botn para llamar al mtodo de pruebas que hemos hecho en la clase de acceso a datos.

using using using using using using

System; System.Drawing; System.Collections; System.ComponentModel; System.Windows.Forms; System.Data;

namespace Pruebas { public class MainFrm : System.Windows.Forms.Form { private System.Windows.Forms.Button btnProbar; private System.ComponentModel.Container components = null; public MainFrm() { InitializeComponent(); } protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } [STAThread] static void Main() { Application.Run(new MainFrm()); } private void btnProbar_Click(object sender, System.EventArgs e) { MessageBox.Show ("Esto es el botn de pruebas","PRUEBA", MessageBoxButtons.OK,MessageBoxIcon.Information); } } }

Ahora COMPILAREMOS LA SOLUCIN, para verificar que no hay errores sintcticos:

Una vez tenemos dos proyectos que compilan correctamente, aadiremos la referencia necesaria para poder utilizar la clase desde el proyecto de pruebas. Recuerda que cuando tenemos clases en un proyecto diferente, hemos de aadir su referencia. Como estamos trabajando todo en la misma solucin aadiremos la referencia al proyecto, no la referencia a la DLL.

Elegimos el proyecto, lo seleccionamos y aceptamos.

Ahora ponemos el using correspondiente, y probamos que funciona:using using using using using using using System; System.Drawing; System.Collections; System.ComponentModel; System.Windows.Forms; System.Data; GestionLib;

namespace Pruebas { public class MainFrm : System.Windows.Forms.Form { . . . . . . . . . . . . private void btnProbar_Click(object sender, System.EventArgs e) { Gestion G = new Gestion(); MessageBox.Show ("Resultado = " + G.MetodoDePruebas(4,7) ,"PRUEBA", MessageBoxButtons.OK,MessageBoxIcon.Information); } } }

Hemos comentado la necesidad de tener datos globales en los programas. En este caso, el objeto de acceso a datos ser nico en toda la aplicacin, y ser global. Para conseguirlo, crearemos una clase ESTTICA en el programa de pruebas, y lo colocaremos alli.using System; using GestionLib; namespace Pruebas { public class Global { public static Gestion Glb = new Gestion(); } }

Ahora, en el programa de pruebas, utilizaremos este objeto global para acceder a los datos:private void btnProbar_Click(object sender, System.EventArgs e) { MessageBox.Show ("Resultado = " + Global.Glb.MetodoDePruebas(4,7) ,"PRUEBA", MessageBoxButtons.OK,MessageBoxIcon.Information); }

De aqu en adelante, podremos utilizar Global.Glb para acceder al nico objeto instanciado en toda la aplicacin de la clase de acceso a datos.

ACCESO A LA BASE DE DATOS Ahora vamos a ver cmo crear la conexin con la base de datos, cmo hacer una consulta, cmo construir el mtodo que permite acceder desde el programa de pruebas, cmo llamarlo, y cmo presentar la informacin. Para utilizar las clases de acceso a bases de datos hay que incluir los using correspondientes. Nos har falta una conexin con la base de datos, que se ha de abrir. Construiremos un mtodo que permite obtener los artistas cuyo nombre cumple un filtro especificado:using System; using System.Data; using System.Data.OleDb; namespace GestionLib { public class Gestion { OleDbConnection Cnx; public void Iniciar () { Cnx = new OleDbConnection ("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\\BDMusika.mdb"); Cnx.Open (); } public DataSet GetArtistas (string Filtro) { OleDbDataAdapter Adp; DataSet Ds = new DataSet(); string sql; sql = "SELECT * " + " FROM Artistas " + " WHERE ART_Nombre LIKE '%" + Filtro.Replace("'","''") + "%'"; Adp = new OleDbDataAdapter(sql, Cnx); Adp.Fill (Ds,"Artistas"); return Ds; } } }

(Slo se muestra en el proyecto LO QUE SE HA DE AADIR, el resto de funciones quedan tal cual estaban). Ahora lo probaremos en el programa de pruebas. Dado que nuestra objeto global NECESITA ABRIR LA CONEXIN al comenzar a ejecutar, llamaremos una sola vez a este mtodo al arrancar el programa.

Hemos puesto un TextBox (txFiltro) y un DBGrid (GArtistas), para presentar la informacin.

Y aprovechando el botn que ya tenemos, colocamos el cdigo necesario para llamar al mtodo y presentar la informacin en la grid.public MainFrm() { InitializeComponent(); Global.Glb.Iniciar(); } private void btnProbar_Click(object sender, System.EventArgs e) { MessageBox.Show ("Resultado = " + Global.Glb.MetodoDePruebas(4,7) ,"PRUEBA", MessageBoxButtons.OK,MessageBoxIcon.Information); DataSet Consulta = Global.Glb.GetArtistas(txFiltro.Text); GArtistas.DataSource = Consulta; GArtistas.DataMember = "Artistas"; GArtistas.Refresh(); }

El resultado de la ejecucin ser el siguiente:

Podemos acceder al DataSet manualmente tambin:private void btnProbar_Click(object sender, System.EventArgs e) { MessageBox.Show ("Resultado = " + Global.Glb.MetodoDePruebas(4,7) ,"PRUEBA", MessageBoxButtons.OK,MessageBoxIcon.Information); DataSet Consulta = Global.Glb.GetArtistas(txFiltro.Text); GArtistas.DataSource = Consulta; GArtistas.DataMember = "Artistas"; GArtistas.Refresh(); string Resultado = ""; foreach (DataRow Tr in Consulta.Tables["Artistas"].Rows) Resultado = Resultado + (string) Tr["ART_Nombre"] + "\n"; MessageBox.Show (Resultado,"Acceso manual",MessageBoxButtons.OK); }

Hasta ahora hemos construido un proyecto que da como resultado un proyecto cliente local.

CREACION DE UNA APLICACIN CLIENTE-SERVIDOR MEDIANTE REMOTING Creamos el proyecto del servidor:

Primero hemos de indicar que el objeto de acceso a datos funciona en modo remoto, y tambin incluiremos un mensaje en la consola, para verificar que se ejecuta el programa servidor.using System; using System.Data; using System.Data.OleDb; namespace GestionLib { public class Gestion : MarshalByRefObject { . . . . . . . . . . . . . . . . . public DataSet GetArtistas (string Filtro) { Console.WriteLine ("Ejecucion del mtodo GetArtistas: " + Filtro); . . . . . . . . . . . . . . . . } } }

Ahora escribimos el cdigo del servidor, que nicamente crea el objeto y lo registra para que pueda ser accedido remotamente (a travs del puerto 1001, por ejemplo):using using using using using System; System.Runtime.Remoting.Channels.Http; System.Runtime.Remoting.Channels; System.Runtime.Remoting; GestionLib;

namespace Servidor { class Servidor { [STAThread] static void Main(string[] args) { HttpChannel Canal = new HttpChannel(1001); ChannelServices.RegisterChannel(Canal); Gestion Obj = new Gestion(); RemotingConfiguration.RegisterWellKnownServiceType(typeof(Gestion), "Gestion.soap", WellKnownObjectMode.SingleCall); RemotingServices.Marshal(Obj, "Gestion.soap"); Console.WriteLine("Pulsa INTRO para cerrar el servidor"); Console.ReadLine(); } } }

Es necesario en el proyecto servidor aadir dos referencias: - Referencia a System.Runtime.Remoting (.NET) - Referencia a GestionLib (Proyecto) El cliente deber ser modificado tambin para que utilice este servidor, en lugar de crear al objeto por su cuenta de forma local:using System; using GestionLib; namespace Pruebas { public class Global { // public static Gestion Glb = new Gestion(); public static Gestion Glb = (Gestion) Activator.GetObject(typeof(Gestion), "http://localhost:1001/Gestion.soap"); } }

Se ha de reemplazar la lnea que hay comentada (la que creaba fsicamente el objeto de la librera) por la siguiente (que enlaza con el objeto existente en el servidor, que ya estar en ejecucin). Para probar el proyecto, hemos de tener en cuenta que ahora vamos a ejecutar DOS PROGRAMAS: El cliente y el servidor. No podemos ejecutar dos programas a la vez en el entorno de desarrollo de .NET, as que GENERAMOS la solucin, y ejecutamos a mano el programa servidor:

Al ejecutarlo, veremos el programa de consola que hemos creado:

Ejecutamos el cliente desde el entorno de desarrollo de .NET, y vemos que aparentemente no hay ninguna diferencia con lo que ocurra antes. Sin embargo, si miramos en la pantalla de ejecucin del servidor veremos lo siguiente:

Vemos que, efectivamente, el cdigo de la clase de acceso a datos se est ejecutando en el programa servidor. Para realizar la prueba final, podemos COPIAR el servidor a otro ordenador. Deberemos copiar el directorio BIN\DEBUG del proyecto servidor en la mquina destino. Tambin tenemos que acordarnos de poner la base de datos en su sitio correcto (mirar la instruccin de creacin del OleDbConnection). En el cliente hemos de cambiar la direccin de la mquina donde se va a buscar al objeto de ejecucin remota. Donde pone localhost, debemos poner el nombre o la direccin IP de la mquina servidora.public static Gestion Glb = (Gestion) Activator.GetObject(typeof(Gestion), "http://localhost:1001/Gestion.soap"); public static Gestion Glb = (Gestion) Activator.GetObject(typeof(Gestion), "http://ManolitoPerez:1001/Gestion.soap");

Ya tenemos nuestra aplicacin cliente-servidor en modo remoting.

CREACIN DE UNA APLICACIN CLIENTE-SERVIDOR MEDIANTE WEB-SERVICES Creamos el proyecto del servidor:

Es un proyecto de tipo ASP.NET Web Service. Se crea en localhost, ya que debe activarse mediante el servidor Web de la mquina. Aadimos la referencia a [GestionLib].using using using using using using using using System; System.Collections; System.ComponentModel; System.Data; System.Diagnostics; System.Web; System.Web.Services; GestionLib;

namespace SrvGestion { public class WGestion : System.Web.Services.WebService { static GestionLib.Gestion Glb = new GestionLib.Gestion (); public WGestion() { //CODEGEN: This call is required by the ASP.NET Web Services Designer InitializeComponent(); Glb.Iniciar(); }

[WebMethod] public DataSet GetArtistas (string Filtro) { return Glb.GetArtistas(Filtro); } } }

Ya podemos probar nuestro servicio mediante el navegador Web:

Estamos viendo el contenido del DataSet, en XML, que ser recibido por la aplicacin cliente. Ahora, en el cliente, aadimos una referencia Web al servidor que acabamos de hacer:

Ahora, hemos de crear el objeto que comunica con el servicio Web:using System; using GestionLib; namespace Pruebas { public class Global { // public static Gestion Glb = new Gestion(); // public static Gestion Glb = (Gestion) Activator.GetObject(typeof(Gestion), "http://localhost:1001/Gestion.soap"); public static ServidorWeb.WGestion Glb = new ServidorWeb.WGestion(); } }

Por esto es importante llamar a los mtodos del servicio Web igual que a los del objeto de manejo de datos. Ahora no hay que modificar NADA MS del programa cliente para que funcione exactamente igual que antes, pero va servicios Web. Slo tenemos que aadir un WebMethod Iniciar y otro MetodoDePruebas para que no haya ningn problema y todo sea compatible.

Cuando hacemos modificaciones en el servicio Web, hemos de ACTUALIZAR LA REFERENCIA en el cliente. Esto se hace de la siguiente manera:

Nos ha quedado una solucin con los siguientes componentes: