Objetos remotos
(Primera parte)

Fecha: 21/Jul/2004 (15/Jul/04)
Autor: Ariel Menendez


Índice:

 

  1. Qué es un objeto remoto

  2. Cómo creo un objeto remoto

  3. Implementar el Shared Assembly

  4. Implementar el Server

  5. Implementar el Client

 


 

 

 

Qué es un objeto remoto.

 

Un objeto remoto como su nombre lo indica, es un objeto que se crea en un equipo (o appDomain) distinto del que se lo esta invocando. O sea, supongamos que en nuestro host estamos corriendo una aplicación que consume servicios de otro host (remoto) estos servicios, por ejemplo, podrían ser, realizar un cálculo, obtener cierta información, en fin. Como estos servicios son utilizados por varios host es necesario mantenerlos centralizado en un único equipo que cumpla la función de Server por lo tanto se define una capa de negocio la cual será expuesta a los clientes mediante una interfase común (entre cliente y servidor) para que se comuniquen y el Server pueda atender las solicitudes del cliente.

Por lo tanto cuando un cliente realiza una petición desde su aplicación la cual consume un servicio remoto, lo que esta haciendo es, mediante un mecanismo – que voy a explicar después – avisarle al servidor que debe crear una instancia de un objeto en particular, ejecutar la acción y devolverle el resultado a quien le hizo dicha petición, o sea, el cliente.

 

Remoting es el proceso de programas o componentes interactuando a través de ciertos límites. Este contexto normalmente requiere de diferentes procesos o host. El mecanismo provee la habilidad de ejecutar métodos sobre servidores remotos pasando parámetros y recibiendo valores. El objeto remoto siempre se mantendrá sobre el Server y solo una referencia de éste será pasada a través de otros hosts.

Cuando un objeto pasa un límite éste es serializado. Este puede ser serializado en binario o en XML. Y una vez qué llega al otro lado es deserializado. Ambos, el servidor y el cliente, mantienen una copia del objeto que siempre será llevado fuera del contexto local y nunca un mensaje viajará de regreso al host del cual el objeto fue originado.

De hecho antes de la serialización y deserialización el objeto copiado es distinguido de un objeto regular.

 

Remoting brinda un flexible y extensible framework, el cual permite diferentes mecanismos de transferencia. Por ejemplo, (http y tcp son soportados por default), encodings como (SOAP y binario soportados por default), y seteos de seguridad (IIS y SSL).

 

Para Internet uno puede elegir entre (http / SOAP) o para una LAN (TCP / Binario).

 

 

 

 

Cómo creo un objeto remoto.

 

En primer lugar, para crear un objeto remoto hay que tener bien en claro cuales son las interfases que se desean utilizar en la aplicación cliente y en que tipo de aplicaciones será utilizado el objeto (Web / win32). Una vez sabido ésto, es necesario definir lo que se conoce como Shared Assembly.

 

Estas interfaces u objetos formarán parte de un assembly el cual contendrá las interfaces en común que utilizará tanto el cliente como el servidor. Además en este assembly irán todos los objetos que podrían ser serializados para poder ser transportados de un contexto a otro.

 

 

 

 

Cuando se crea un objeto remoto, tanto clientes como servidor deben poseer la misma interfase como así también a los objetos serializables que son pasados por valor. Esto da como resultado el hecho de que al menos serán necesarios tres assemblies (uno con la interfase y objetos serializables en común, otro que sea el Server Assembly y otro que sea Client Assembly) ah, olvidé mencionar que todas las clases base que se usen en el servidor deben heredar de la clase MarshalByRefObject, lo cual define que dichas clases serán consumidas por el cliente.

 

El ejemplo que voy a mostrar estará constituido por tres assemblies.

 

Common: Este assembly contiene las interfases, las clases base y los objetos seriabizables en común.

 

Server: Esta assembly contiene la implementación que se realizará del lado del servidor.

 

Client: Este assembly contiene un ejemplo de cómo consumir el servicio de un objeto remoto.

 

Bueno, manos a la obra:

 

 

 

 

Implementar el assembly Common

 

El primer paso será definir una interfase que utilizaran tanto el servidor como el cliente, por lo tanto será una interfase ubicada en el assembly Common.

 

public interface IUserManager

{

            User getUser (string key);

}

 

 
 

 


Una vez que tengo la interfase que necesito utilizar en los dos ámbitos tengo que realizar la clase del objeto seriablizable que pasara por valor. Noten que en la definición del método que posee la interfase el tipo de retorno es de tipo User, por lo tanto es necesario definir esta clase.

 


 

[Seriablizable]

public class User

{

            public string Name;

            public string LastName;

 

            public User()

            {

            Console.WriteLine(“Objeto creado”);

}

 

}

 

 

 

 

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Es importante que esta clase se encuentre marcada como serializable, de lo contrario, al intentar pasarla por valor, nos tirará una excepción.

 

Una vez creado el assembly que compartirán tanto el cliente como el servidor podemos realizar el assembly del Server.

 

 

 

 

Implementar el Server

 

En el Server vamos a crear la clase UserManager la cual heredará de MarshalByRefObject (Recuerden que para que una clase pueda ser de ejecución remota es necesario que sí o sí herede de esta clase, o por lo menos su clase base), y además implementará la interfase previamente definida en el assembly Common.

 

Para poder trabajar en el servidor es necesario contar con la ayuda de algunos espacios de nombre extra los cuales tengo que declarar con la directiva using  en la clase UserManager.

 

Los espacios de nombre son los que muestro a continuación:

 

using System.Runtime.Remoting;

using Common;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

 
 

 


Es importante aclarar que el espacio de nombre System.Runtime.Remoting.Channels.Http no lo van a encontrar por sí solo, para que se los muestre  al presionar el punto es necesario antes registrar el assembly System.Runtime.Remoting.

 

Nota: No voy a explicar como hacer para registrar un assembly porque se supone que si preocuparon por leer este artículo el asunto de la registración de assemblies dentro de un proyecto ya lo tienen más que claro. ¿O no?

 

 

Una vez que agregamos los espacios de nombre necesarios para trabajar comenzamos a realizar nuestra clase remota que correrá del lado del servidor.

 

class UserManager : MarshalByRefObject, IUserManager

{

            public UserManager()

            {

                        Console.WriteLine(“Objeto creado”);

            }

 

            public User getUser(string key)

            {

                        User user  = new User();

                        user.Name = “Ariel”;

                        user.LastName = “Menendez”;

           

                        return user;

            }

}

 
 

 

 


De esta forma realizamos nuestro objeto remoto el cual podrá ser invocado desde un cliente.

 

Ahhhhh me había olvidado el proyecto que pueden crear para realizar las pruebas puede ser de tipo Console; esta es la forma mas fácil de probar todo esto.

 

Bueno, una vez aclarado esto, le paso a decir que ahora deberíamos tener que programar nuestro método Main de la consola para poder definitivamente crear el servidor el cual se quedará escuchando en un puerto determinado cualquier petición que le llegue.

 

 

La forma de programar el método Main para que cumpla su función de Server es la siguiente:

 

Class Server

{

            Public static void Main(string[] args)

            {

                        HttpChannel chl = new HttpChannel(2345);

                        ChannelServices.RegisterChannel(chl);

 

                        RemotingConfiguration.RegisterWellKnowServiceType(

                                                                                    typeof(UserManager),

                                                                                    “UserManager.soap”,

                                                                                    WellKnowObjectMode.Singleton);

 

                        Console.ReadLine();

           

 

}

 

 

}

 

 
 

 

 

 


Bueno, así de fácil se realiza un servidor que se quede escuchando en un puerto determinado.

 

 

HttpChannel chl = new HttpChannel(2345);

 

Esta primera línea de código lo que está indicando es que el servidor debe utilizar el Puerto 2345 para recibir las peticiones. Este puerto se debe elegir de un total de 65536 puertos, pero hay que tener en cuenta que un puerto no puede ser utilizado por dos servicios al mismo tiempo en un mismo host, por lo tanto antes de elegir un puerto es necesario estar seguro de que dicho puerto no está siendo utilizado por otro servicio.

 

 

ChannelServices.RegisterChannel(chl);

 

Esta línea de código indica que el canal esta siendo registrado en el sistema de remoting. Esto permite que las solicitudes entrantes sean enviadas a los objetos correspondientes.

 

 

 

RemotingConfiguration.RegisterWellKnowServiceType(

                                                                        typeof(UserManager),

                                                                        “UserManager.soap”,

                                                                        WellKnowObjectMode.Singleton);

 

Esta línea indica que la clase UserManager ha sido registrada como WellKnowServiceType lo cual indica que el objeto será de tipo SAO (esto lo voy a explicar en otro momento, por ahora crean esto que es tal cual se los digo). El siguiente parámetro indica la URL que se deberá invocar desde el cliente para consumir el servicio “UserManager.soap”, el .soap no es obligatorio pero debería ser usado para mantener consistencia. Y por ultimo, se define de qué modo se creara el objeto. En este caso optamos por el modo singleton aunque en un caso real deberíamos realizar un análisis antes de tomar esta decisión puesto que los modos pueden ser tanto singleton o singlecall y la diferencia entre uno y otro es que con slingleton se crea una única instancia del objeto para todas las peticiones, lo cual hacer que el objeto sea de tipo statefull, y con singlecall se crea un objeto para cada petición realizada, por lo tanto cuando es dejado de usar por el cliente, el objeto muere, este modo se denomina stateless.

 

 

Bueno así de fácil se crea un servidor básico de remoting. Ahora que ya tenemos el servidor programado podemos presionar F5 para hacerlo correr y dejarlo a la espera de alguna petición.

 

 

 

Implementar el cliente.

 

Bueno, el primer paso a realizar para crear el cliente que consumirá el objeto remoto que tenemos a la espera, será abrir un nuevo framework.

Una vez hecho esto es necesario que un nuevo proyecto Console sea creado y que luego le agreguemos los mismos espacios de nombre que le habíamos agregado al Server.

 

Excelente. Ahora vamos a comenzar con la programación de nuestro cliente.

 

A continuación, se expone el código necesario para poder realizar una invocación de un objeto remoto.

 

 

class Client

{

            public static void Main(string[] args)

            {

                        HttpChannel channel = new HttpChannel();

                        ChannelServices.RegisterChannel(channel);

 

                        IUserManager userMgr = (IUserManager)Activator.GetObject(

                                                            typeof(IUserManager),

                                                            “http://localhost:2345/UserManage.soap”);

 

                        User user = userMgr.GetUser(“Ariel”);

 

                        Console.WriteLine(“El usuario es {0}, {1}”, user.LastName,

user.Name);

 

                        Console.ReadLine();

 

                       

}

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Bueno, ahora que ya tenemos el código necesario para realizar la ejecución remota de un objeto vamos a ver línea por línea de que se trata.

 

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

 

Esta primera parte como verán es muy parecida, o mejor dicho igual a la primera parte del código del servidor. La única diferencia respecto del servidor es que el puerto a utilizar no se declara en forma explícita. Lo que suceda acá es que al no pasarle el puerto al constructor del HttpChannel lo que le estamos diciendo a la clase es que tome un puerto en forma dinámica.

 

 

IUserManager userMgr = (IUserManager)Activator.GetObject(

                                                            typeof(IUserManager),

                                                            http://localhost:2345/UserManage.soap”);

 

 

En esta parte del código lo que se está haciendo es declarar una variable de tipo IUserManagar la cual guardará en su interior la creación del objeto remoto.

En lugar de realizar una instancia del objeto con el operador New lo que se hacer es realizar esta instancia (remota) con el método GetObject de la clase Activator.

Este método recibe como parámetro el tipo de objeto que será instanciado y la url donde debe ir a buscar la instancia. ¿Fácil no?

 

Una vez obtenido el objeto, ya estamos en condiciones de utilizar su funcionalidad del lado del cliente.

 

En este caso teníamos una clase serializable denominada User la cual estaba en el assembly compartido por el Server y el Client. Por lo tanto, definimos una variable de tipo User y con la variable userMgr utilizamos el método GetUser, el cual me retorna un objeto de tipo User.

 

Una vez cargada esta variable ya estamos en condiciones de invocar sus campos.

 

Y gualá…. ya tenemos nuestra primera aplicación que invoca un objeto remoto.

 

 


ir al índice

Índice de la sección dedicada a punto NET (en el Guille)

Fichero con el código de ejemplo: menendea_Objetos_remotos_primera_parte.zip - Tamaño 45KB