XML, Distribución y Componentes
Tema 6 – Aplicaciones Distribuidas: .NET Remoting
http://paginaspersonales.deusto.es/dipina/MasterISW/
Dr. Diego Lz. de Ipiña Gz. de Artazahttp://paginaspersonales.deusto.es/dipina (Personal)
http://www.morelab.deusto.es (Research Group)http://www.smartlab.deusto.es (Research Lab)
http://www.ctme.deusto.es (Cátedra de Telefónica Móviles)http://www.tecnologico.deusto.es (Tecnológico-Fundación Deusto)
2/80
Temario
Procesamiento XML en .NET (21 y 22 Febrero) Estándar .NET [XML.NET] Soporte XML [XML-SAX, XML-DOM, Validación] XSL [XPath, XSLT, Scripts, Objetos de extensión]
Aplicaciones distribuidas (23 Febrero, 5 Marzo) XML/SOAP .NET Remoting Mensajería
Componentes .NET (6 y 7 Marzo) Metadatos y Reflexion Componentes .NET y Enterprise Services Complementos Interoperabilidad COM y P/Invoke COM+ y MTS MSMQ (colas de mensajes)
3/80
Contenidos Parte Aplicaciones Distribuidas
WebServices y SOAP .NET Remoting Mensajería
4/80
Introducción
ASP.NET es la herramienta adecuada para la construcción de clientes ligeros que sólo visualizan lenguaje de marcado a través de un navegador
Hay aplicaciones que se benefician de una mayor acoplamiento entre el cliente y el servidor Se comportan mejor en la comunicación a dos bandas entre el
cliente y el servidor Utilizan la red de manera más óptima Facilitan el mantenimiento del estado de sesiones
El espacio de nombres System.Runtime.Remoting provee la infraestructura para el desarrollo de este tipo de aplicaciones al estilo de DCOM
5/80
.NET Remoting
Remoting sustituye a la tecnología DCOM para crear aplicaciones distribuidas sobre plataformas Windows.
Remoting proporciona una arquitectura orientada a objetos, que permite desarrollar de forma sencilla aplicaciones distribuidas.
6/80
Características
NET Remoting permite construir aplicaciones distribuidas.
Todos los componentes de aplicación pueden concentrarse en un único ordenador o en múltiples servidores alrededor de Internet.
.NET Remoting permite a las aplicaciones cliente utilizar objetos ubicados en cualquier ordenador conectado a la Red.
Podemos decir que Remoting permite invocar métodos y pasar objetos más allá de los dominios de nuestra aplicación.
7/80
Características
La arquitectura .NET remoting es flexible, permitiendo una fácil personalización de la aplicación.
En vez de utilizar mecanismos propietarios Remoting soporta estándares ya existentes como: SOAP (Simple Object Access Protocol) HTTP y TCP como protocolo de comunicación.
Proporciona servicios y canales de comunicación que transmiten mensajes entre aplicaciones remotas.
Proporciona formateadores que codifican y decodifican los mensajes que se transmiten por los canales.
8/80
Conceptos Básicos
Un clase es remota cuando puede ser usada por clientes en otro dominio de aplicación: en el mismo proceso, en otro proceso o en otras máquinas
Para construir una clase remota en primer lugar hay que hacer que la clase derive de: System.MarshalByRefObject
public class RemotableClass: MarshallByRefObject { ...}
9/80
Conceptos Básicos
Client
ProxyMarshall-by-
reference object
Client application domain Server application domain
Channel
10/80
Conceptos Básicos
1. Cuando un cliente crea una instancia de RemoteClass, realmente se crea un proxy de la misma
Llamadas recibidas por el proxy son transmitidas al objeto remoto a través de un canal que conecta los dos dominios de aplicación
El cliente sólo mantiene una referencia al objeto, no una copia del mismo
11/80
Conceptos Básicos
2. Como segundo paso en hacer un objeto remoto hay que registrar la clase para que pueda ser activada desde otro dominio de aplicación
Hay dos modos de registrar un objeto, a través de dos métodos estáticos en System.Runtime.Remoting.RemotingConfiguration:
RegisterActivatedServiceType RegisterWellKnownServiceType
RemotingConfiguration.RegisterWellKnownServiceType ( typeof(RemotableClass), // Remotable class “RemoteObject”, // URI of remotable class WellKnownObjectMode.SingleCall // Activation mode);
12/80
Tipos de objetos remotos
(Según sea su modelo de activación ).3. Antes de poder utilizar un objeto remoto este debe ser creado e
inicializado, en un proceso llamado activación. La activación puede ser de varios tipos:
Hay dos modos de activar un objeto en la parte servidora: WellKnownObjectMode.SingleCall, crea una nueva instancia de
RemotableClass por cada llamada invocada por un cliente WellKnownObjectMode.Singleton, crea una instancia de RemotableClass
para procesar todas las llamadas de los clientes Cliente
13/80
Conceptos Básicos
5. Para hacer que la clase RemotableClass sea accesible por clientes remotos, el proceso servidor tiene que crear y registrar un canal (channel)
Un canal provee un conducto para la comunicación entre un objeto y un cliente remoto
.NET ofrece dos tipos de canales: System.Runtime.Remoting.Channels.Tcp.TcpServerChannel
acepta conexiones TCP de clientes remotos Es el más eficiente
System.Runtime.Remoting.Channels.Http.HttpServerChannel, que acepta conexiones HTTP Permite usar IIS como agente de activación
TcpServerChannel channel = new TcpServerChannel(1234);ChannelServices.RegisterChannel(channel);
14/80
Conceptos Básicos
Una aplicación cliente que quiera crear una instancia remota de RemotableClasss tiene que registrarse por su parte
Hay dos tipos de canales para clientes: HttpClientChannel -> permite a un cliente hablar con un servidor que
escucha en un HttpServerChannel TCPClientChannel -> permite a un cliente hablar con un servidor que
escucha en un TCPServerChannel Si el cliente quiere usar new para instanciar un objeto remoto, debe
registrar la clase remota en el dominio de aplicación local RegisterWellKnownClientType registra una clase en el cliente
que está registrada como RemotingConfiguration.RegisterWellKnownServiceType en el servidor:
15/80
Conceptos Básicos
Para que un Cliente se pueda comunicar con un objeto remoto necesitamos un camino a través del que se pueda realizar la transferencia de datos. Este camino se llama canal (Channel). Un canal toma datos, crea un paquete según las especificaciones de un protocolo y envía el paquete a otro ordenador.
Los canales son utilizados para transportar los mensajes desde y hacia los objetos remotos. Cuando un cliente invoca remotamente un método, los parámetros y otros detalles referidos a la invocación son transportados a los objetos por medio del canal. De la misma forma son transportadas las respuestas a esa invocación.
16/80
Canales
Dos tipos de canales HTTP ó TCP. Canales TCP: Usan TCP para comunicarse y transmiten datos en
formato binario. Son adecuados cuando el rendimiento es lo importante.
El canal TCP tiene un rendimiento mayor ya que se conecta directamente a un puerto seleccionado por nosotros.
Canales http: Usan HTTP para comunicarse. Lo más normal es que transporten mensajes de tipo SOAP. Son adecuados cuando lo que prima es la interoperabilidad.
El canal HTTP es comúnmente utilizado para las comunicaciones en Internet.
17/80
SOAP
Simple Object Access Protocol Gran parte de la capacidad de .NET Remoting para operar con diferentes
entornos reside en SOAP. Aunque no es el protocolo más eficiente, permite gran flexibilidad. SOAP es un protocolo basado en XML que especifica un mecanismo
mediante el cual aplicaciones distribuidas pueden intercambiar información independientemente de la plataforma
Aunque SOAP utiliza HTTP para su transporte, SOAP podría utilizar cualquier protocolo de transporte (pe SMTP).
http://www.w3.org/TR/SOAP/.
18/80
Conceptos básicos
TcpClientChannel channel = new TcpClientChannel();ChannelServices.RegisterChannel(channel);RemotingConfiguration.RegisterWellKnownClientType( typeof(RemotableClass), // Remotable class “tcp://localhost:1234/RemoteObject” // URL of remotable
class);
Una vez que el cliente y el servidor han efectuado sus registros correspondientes se crea la instancia de RemotableClass:
RemotableClass rc = new RemotableClass();
19/80
Compatibilidad vs. Rendimiento
20/80
Arquitectura Canal Cliente
21/80
Arquitectura Canal Servidor
22/80
Tu primera aplicación con .NET Remoting
Aplicación que devuelve a clientes remotos la hora del sistema
Tres componentes: Una DLL llamada ClockServer.dll que contiene la clase Clock
Un servidor llamado TimeServer.exe que registra Clock para la activación remota
Un cliente (TimeClient.exe) que activa Clock remotamente
23/80
ClockServer.cs
using System;
public class Clock: MarshalByRefObject{
public string GetCurrentTime() {
return DateTime.Now.ToLongTimeString();}
}
24/80
TimeServer.cs
using System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;
class MyApp{
static void Main() {
// tcp://localhost:1234/ClockTcpServerChannel channel = new TcpServerChannel(1234);ChannelServices.RegisterChannel(channel);RemotingConfiguration.RegisterWellKnownServiceType(
typeof(Clock), "Clock", WellKnownObjectMode.SingleCall);
Console.WriteLine("Press Enter to terminate ...");Console.ReadLine();
}
}
25/80
TimeClient.cs
using System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;
class MyApp{
static void Main() {
TcpClientChannel channel = new TcpClientChannel();ChannelServices.RegisterChannel(channel);RemotingConfiguration.RegisterWellKnownClientType(
typeof(Clock), "tcp://localhost:1234/Clock");
Clock clock = new Clock();Console.WriteLine(clock.GetCurrentTime());
}}
26/80
Compilando y ejecutando ejemplo Clock
1. Para compilar ClockServer.dll, TimeServer.exe y TimeClient.exe:
csc /t:library clockserver.cs csc /r:clockserver.dll TimeServer.cs csc /r:clockserver.dll TimeClient.cs
2. Empieza en una nueva consola para el servidor: start TimeServer.exe
3. Haz lo mismo para el cliente: start TimeClient.exe
4. Obsérvese que si se desea que el cliente y el servidor estén en diferentes máquinas entonces será necesario copiar ClockServer.dll al cliente, ya que para construir el proxy .NET extrae metadata de ClockServer.dll
27/80
Configuración Declarativa
Las clases TimeServer y TimeClient usan información embebida en el código para registrar canales y clases remotas
El problema es que si deseamos cambiar algún detalle hay que recompilar
El registro declarativo toma información de un fichero CONFIG y se activa llamando al método estático RemoteConfiguration.Configure
Para modificar el cliente para activar el objeto Clock en otra máquina es tan sencillo como editar el fichero TimeClient.exe.config
La información a cambiar no es modificable por cualquier usuario y además se puede borrar accidentalmente
Elegir entre registro declarativo o programático depende de que es más importante si conveniencia o robusted.
28/80
ClockServer.cs
using System;public class Clock : MarshalByRefObject{ public string GetCurrentTime () { return DateTime.Now.ToLongTimeString (); }}
29/80
TimeServer.cs
using System;using System.Runtime.Remoting;
class MyApp{ static void Main () { RemotingConfiguration.Configure
("TimeServer.exe.config"); Console.WriteLine ("Press Enter to
terminate..."); Console.ReadLine (); }}
30/80
TimeServer.exe.config
<configuration> <system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" type="Clock,
ClockServer" objectUri="Clock" /> </service> <channels> <channel ref="tcp server" port="1234" /> </channels> </application> </system.runtime.remoting></configuration>
31/80
TimeClient.cs
using System;using System.Runtime.Remoting;
class MyApp{ static void Main () { RemotingConfiguration.Configure
("TimeClient.exe.config"); Clock clock = new Clock (); Console.WriteLine (clock.GetCurrentTime ()); }}
32/80
TimeClient.exe.config
<configuration> <system.runtime.remoting> <application> <client> <wellknown type="Clock, ClockServer" url="tcp://localhost:1234/Clock" /> </client> <channels> <channel ref="tcp client" /> </channels> </application> </system.runtime.remoting></configuration>
33/80
Server Activation vs. Client Activation
Hay dos tipos de objetos remotos: Server-activated objects
Se registran con RegisterWellKnownServiceType y RegisterWellKnownClientType
Cuando el cliente invoca new sólo se crea un proxy, el objeto no se crea hasta que una invocación es recibida
Sólo se pueden usar constructores por defecto sin parámetros Client-activated objects
Se registran con RegisterActivatedServiceType y RegisterActivatedClientType
El objeto remoto se crea en la parte servidora inmediatamente después de llamar a new
Se pueden activar con constructores con parámetros
34/80
Server Activation vs. Client Activation
Cuando registras un objeto activado en la parte servidora se especifica como modo de activación: WellKnownObjectMode.SingleCall, que crea una única instancia de un
objeto por cada petición WellKnownObjectMode.Singleton, que crea una única instancia y la usa para
servir peticiones Permite mantener estado entre invocaciones No sincroniza las llamadas invocadas sobre métodos
Los objetos activados en la parte del cliente ofrecen otro modo de activación Cada llamada a new por un cliente crea una instancia que preserva estado de una
llamada a otra. Si quieres mantener estado por cada cliente deberás utilizar este modo de
activación. Ejemplo StopWatch ilustra el uso de client-activated objects
35/80
Stopwatch.cs
using System;
public class Stopwatch : MarshalByRefObject{ DateTime mark = DateTime.Now; public void Start () { mark = DateTime.Now; }
public int Stop () { return (int) ((DateTime.Now -
mark).TotalMilliseconds); }}
36/80
StopWatchServer.cs
using System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;
class MyApp{ static void Main () { TcpServerChannel channel = new TcpServerChannel (1234); ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterActivatedServiceType (typeof (Stopwatch));
Console.WriteLine ("Press Enter to terminate..."); Console.ReadLine (); }}
37/80
StopWatchClient.csusing System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;
class MyApp{ static void Main () { TcpClientChannel channel = new TcpClientChannel (); ChannelServices.RegisterChannel (channel);
RemotingConfiguration.RegisterActivatedClientType (typeof (Stopwatch), "tcp://localhost:1234");
Stopwatch sw = new Stopwatch (); sw.Start ();
Console.WriteLine ("Press Enter to show elapsed time..."); Console.ReadLine ();
Console.WriteLine (sw.Stop () + " millseconds"); }}
38/80
Pasando Objetos con .NET Remoting
Puede darse el caso de que algún parámetro de entrada o salida de algún método de nuestro objeto remoto sea un objeto.
En el caso que el objeto sea pasado por valor el marco de Remoting se encarga de hacer una copia completa del objeto para que pueda ser enviado a través de un canal. En el .NET Framework existen los formateadores de serialización que se encargan de codificar y decodificar los mensajes. .NET, binario (System.Runtime.Serialization.Formatters.Binary) SOAP (System.Runtime.Serialization.Formatters.SOAP).
A los objetos que contengan mayor cantidad de información, será adecuado pasarlos por referencia.
39/80
Por Valor
40/80
Por Referencia
41/80
Los métodos Activator.GetObject y Activator.CreateInstance
Un objeto no sólo se puede activar a través del operador new
A través de los siguientes métodos estáticos definidos en System.Activator también se pueden registrar objetos: GetObject se usa para activar objetos en la parte servidora CreateInstance se usa para activar objetos en la parte cliente
Además en la parte cliente ya no es necesario usar RegisterActivatedClientType o RegisterWellKnownClientType
42/80
Los métodos Activator.GetObject y Activator.CreateInstance
Ejemplo (antes):RemotingConfiguration.RegisterWellKnownClientType(typeof(Clock),
“tcp://localhost:1234/Clock”);Clock clock = new Clock();
RemotingConfiguration.RegisterActivatedClientType(typeof(Stopwatch), “tcp://localhost:1234”);
Stopwatch sw = new Stopwatch(); Después:Clock clock = (Clock)Activator.GetObject(typeof(Clock),
“tcp://localhost:1234/Clock”);
object[] url = {new UrlAttribute(“tcp://localhost:1234”)};Stopwatch sw = (Stopwatch)Activator.CreateInstance(typeof(Stopwatch), null,
url); ¿Por qué usar GetObject o CreateInstance?
Porque pueden usarse para activar un objeto remoto sin poseer otro conocimiento de ese objeto aparte de la url y una interfaz que soporta el tipo
Iclock ic = (Iclock)Activator.GetObject(typeof(Iclock), “tcp://localhost:1234/Clock”);
43/80
Usando Interfaces para Declarar Contratos en Remoting I
// csc /t:library IClock.cspublic interface IClock{
string GetCurrentTime();}
// csc /t:library /r:IClock.dll ClockService.csusing System;public class Clock : MarshalByRefObject, IClock{ public string GetCurrentTime () { return DateTime.Now.ToLongTimeString (); }}
44/80
Usando Interfaces para Declarar Contratos en Remoting II
// csc /r:ClockService.dll;IClock.dll TimeServer.csusing System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;
class MyApp{
static void Main() {
RemotingConfiguration.Configure ("TimeServer.exe.config");
Console.WriteLine("Press Enter to terminate ...");Console.ReadLine();
}}
45/80
Usando Interfaces para Declarar Contratos en Remoting III
// TimeServer.exe.config<configuration> <system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" type="Clock, ClockService" objectUri="Clock" /> </service> <channels> <channel ref="tcp server" port="1234" /> </channels> </application> </system.runtime.remoting></configuration>
46/80
Usando Interfaces para Declarar Contratos en Remoting IV
// csc /r:IClock.dll TimeClient.csusing System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Tcp;class MyApp{
static void Main() {
RemotingConfiguration.Configure ("TimeClient.exe.config");
WellKnownClientTypeEntry[] serviceMetadata = RemotingConfiguration.GetRegisteredWellKnownClientTypes();
47/80
Usando Interfaces para Declarar Contratos en Remoting V
if (serviceMetadata.Length > 0){
IClock clock = (IClock)Activator.GetObject(typeof(IClock), serviceMetadata[0].ObjectUrl);
while (true){
Console.WriteLine(clock.GetCurrentTime());}
}}
}
48/80
Usando Interfaces para Declarar Contratos en Remoting VI
<configuration> <system.runtime.remoting> <application> <client> <wellknown type="IClock, IClock" url="tcp://localhost:1234/Clock" /> </client> <channels> <channel ref="tcp client" /> </channels> </application> </system.runtime.remoting></configuration>
49/80
Ciclo de vida de objetos y leasing
En DCOM un objeto es destruido cuando su contador de referencias alcanza el valor 0
En .NET: Los objetos single-call server-activated viven por la duración de una llamada, luego
pueden ser reclamados por el garbage collector Los objetos singleton server-activated o client-activated trabajan de manera
diferente: Su duración de vida es controlado por leases que pueden ser manipulados programática o
declarativamente. Un lease es un objeto que implementa la interfaz ILease:
InitialLeaseTime: cuánto vive el objeto sin recibir una llamada RenewOnCallTime: a cuánto se actualiza el lease cada vez que se recibe una llamada CurrentLeaseTime: cuánto queda antes que se desactive el objeto
Por defecto: InitialLeaseTime (5 mins), RenewOnCallTime (2 mins) Si un objeto no se llama en los primeros 5 minutos o en 2 minutos después de haberse invocado por
última vez se reciclaría Los valores por defecto pueden ser cambiados:
Especificando tiempos de leasing en un fichero de configuración Sobreescribiendo MarshallByRefObject.InitializeLifetimeService en la clase remota
50/80
Ciclo de vida de objetos y leasing
Ejemplo fichero CONFIG: Inicializa InitialLeaseTime y RenewOnCalltime a 20 y 10 minutos
respectivamente M significa minutos, D días, H horas, S segundos y MS milisengundos Un número si sufijo indica segundos
El proceso servidor debe registrar el fichero con RemotingConfiguration.Configure
<configuration> <system.runtime.remoting> <application>
<!–- colocar después de elemento channels --> <lifetime leasetime=“20M” renewOnCallTime=“10M”/> </application> </system.runtime.remoting></configuration>
51/80
Ciclo de vida de objetos y leasing
Ejemplo configuración leasing programática: Hay que sobreescribir el método InitializeLifetimeService
using System;using System.Runtime.Remoting.Lifetime;public class RemotableClass: MarshallByRefObject { public override object InitializeLifetimeService() { // Obtener el lease por defecto ILease lease = (ILease) base.InitializeLifetimeService(); // Modifícalo si no ha sido activado if (lease.CurrentState == LeaseState.Initial) { lease.InitialLeaseTime = TimeSpan.FromMinutes(20); lease.RenewOnCallTime = TimeSpan.FromMinutes(10); } return lease; }}
52/80
Ciclo de vida de objetos y leasing
Si no se quieren utilizar leases, se puede devolver null en el método InitializeLifetimeService: Un objeto así creado no será eliminado por la framework .NET y se
ejecutará mientras el proceso que lo contiene siga ejecutándose
public class Foo: MarshallByRefObject { public override object InitializeLifetimeService() { return null; }}
53/80
Ciclo de vida de objetos y leasing
Un objeto remoto puede adquirir una referencia a su interfaz Ilease llamando a: GetLifetimeService de MarshallByRefObject y luego invocar:
ILease.CurrentLeaseTime ILease.Renew
Un cliente puede obtener una referencia a Ilease a través del método estático: RemotingServices.GetLifetimeServiceRemotableClass rc = new RemotableClass();Ilease lease =
(Ilease)RemotingServices.GetLifetimemService(rc);TimeSpan remaining = lease.CurrentLeaseTime;if (remaining.TotalMinutes < 1.0) lease.Renew(TimeSpan.FromMinutes(10));
La interfaz ILease tiene métodos llamados Register y Unregister que permiten registrar Sponsors. Un sponsor es un objeto que implementa
System.Runtime.Remoting.Lifetime.Isponsor Cuando un lease de un objeto expira la framework .NET no marca el objeto
para ser borrado, sino que primero comprueba si hay algún sponsor registrado y si es así el lease manager invoca los métodos Isponsor.Renewal
54/80
Ejemplo Leasing// csc /t:library RemoteType.cs using System;using System.Runtime.Remoting.Lifetime;using System.Security.Principal;
public class ClientActivatedType : MarshalByRefObject{ // Overrides the lease settings for this object. public override Object InitializeLifetimeService(){ ILease lease = (ILease)base.InitializeLifetimeService(); // Normally, the initial lease time would be much longer. // It is shortened here for demonstration purposes. if (lease.CurrentState == LeaseState.Initial){ lease.InitialLeaseTime = TimeSpan.FromSeconds(3); lease.SponsorshipTimeout = TimeSpan.FromSeconds(10); lease.RenewOnCallTime = TimeSpan.FromSeconds(2); } return lease; } public string RemoteMethod(){ // Announces to the server that the method has been called. Console.WriteLine("ClientActivatedType.RemoteMethod called."); // Reports the client identity name. return "RemoteMethod called. " + WindowsIdentity.GetCurrent().Name; }}
55/80
Ejemplo Leasing
<!– server.exe.config <configuration> <system.runtime.remoting> <application> <channels> <channel ref="http" port="8080"> <serverProviders> <provider ref="wsdl" /> <formatter ref="soap" typeFilterLevel="Full" /> <formatter ref="binary" typeFilterLevel="Full" /> </serverProviders> <clientProviders> <formatter ref="binary" /> </clientProviders> </channel> </channels> <service> <activated type="ClientActivatedType, RemoteType"/> </service> </application> </system.runtime.remoting></configuration>
56/80
Ejemplo Leasing
// csc /r:RemoteType.dll server.cs using System;using System.Runtime.Remoting;
public class Server{public static void Main(string[] Args){
// Loads the configuration file.RemotingConfiguration.Configure("server.exe.config");Console.WriteLine("The server is listening. Press Enter to exit....");
Console.ReadLine(); Console.WriteLine("Recycling memory...");GC.Collect();GC.WaitForPendingFinalizers();
}}
57/80
Ejemplo Leasing// csc /r:RemoteType.dll CAOClient.cs //CAOClient.csusing System;using System.Runtime.Remoting;using System.Runtime.Remoting.Lifetime;
public class Client{ public static void Main(string[] Args){ // Loads the configuration file. RemotingConfiguration.Configure("CAOclient.exe.config"); ClientActivatedType CAObject = new ClientActivatedType(); ILease serverLease =
(ILease)RemotingServices.GetLifetimeService(CAObject); MyClientSponsor sponsor = new MyClientSponsor(); // Note: If you do not pass an initial time, the first request will // be taken from the LeaseTime settings specified in the // server.exe.config file. serverLease.Register(sponsor); // Calls same method on each object. Console.WriteLine("Client-activated object: " + CAObject.RemoteMethod()); Console.WriteLine("Press Enter to end the client application domain."); Console.ReadLine(); }}
58/80
Ejemplo Leasing
public class MyClientSponsor : MarshalByRefObject, ISponsor{ private DateTime lastRenewal;
public MyClientSponsor(){ lastRenewal = DateTime.Now; }
public TimeSpan Renewal(ILease lease){ Console.WriteLine("I've been asked to renew the lease."); Console.WriteLine("Time since last renewal:" + (DateTime.Now -
lastRenewal).ToString()); lastRenewal = DateTime.Now; return TimeSpan.FromSeconds(20); }}
59/80
Ejemplo Leasing
<configuration> <system.runtime.remoting> <application> <channels> <channel ref="http" port="0"> <clientProviders> <formatter ref="binary" /> </clientProviders> <serverProviders> <formatter ref="binary" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> <client url="http://localhost:8080"> <activated type="ClientActivatedType, RemoteType"/> </client> </application> </system.runtime.remoting></configuration>
60/80
Remoting Avanzado
Vamos a ver lo siguiente: Cómo usar IIS como agente de activación Cómo combinar canales HTTP con formateadores
binarios Cómo usar eventos y delegates Como usar invocación asíncrona
61/80
Tipos de aplicación
Necesitamos una aplicación que cree nuestro objeto, lo mantenga en memoria en su propio proceso y a su vez se encargue de configurar el canal de comunicación.
En .NET para poder hospedar objetos remotos en una aplicación podemos optar por: Aplicación de Consola (visto) Servicio del sistema operativo Windows Aplicación Windows de formularios Internet Information Server.
62/80
Usando IIS como Agente de Activación
.NET no ofrece soporte para lanzar procesos servidor automáticamente
Sin embargo, .NET ofrece dos posibilidades para no tener que arrancar procesos de manera manual:
1. Implementar la aplicación servidora como un servicio Deriva de System.ServiceProcess.ServiceBase Sobreescribe los métodos virtuales OnStart y OnStop Ejemplo en remoting\windowsservice
2. Usar IIS como un agente de activación: No necesitas escribir una aplicación servidora para registrar clases remotas y
escuchar peticiones de activación IIS puede autentificar a los invocadores y encriptar datos con SSL IIS lleva a cabo la negociación de puertos Sin embargo, sólo puedes usar canales HTTP
63/80
Usando IIS como Agente de Activación
Accede al directorio examples\remoting\webprojects\ClockServerActivated
Edita el fichero Web.config, que ofrece la configuración necesaria para que IIS active el objeto remoto<configuration>
<system.runtime.remoting><application>
<service><wellknown mode="SingleCall"
type="Clock, ClockServer" objectUri="Clock.rem"/></service>
</application></system.runtime.remoting>
</configuration> IIS requiere que la clase remota se encuentre en un directorio virtual que no
es wwwroot, siempre que se desee crear un client-activated object Web.config debe ser instalado en un directorio virtual separado y la DLL en el
subdirectorio bin Fichero README.txt incluido indica cómo crear un directorio virtual
64/80
Canales HTTP y formateadores binarios
El uso de canales HTTP es obligatorio si queremos usar IIS como agente de activación Codifican las llamadas en SOAP, son muy verbosos y poco eficientes
.NET Remoting ofrece una arquitectura pluggable que permite elegir el tipo de canal a utilizar así como el formato en el que se comunican los mensajes dentro del canal
Por defecto los canales HTTP usan para serializar y deserializar mensajes: SoapClientFormatterSinkProvider SoapServerFormatterSinkProvider
Estos formateadores pueden ser reemplazados por BinaryClientFormatterSinkProvider y BinaryServerFormatterSinkProvider para codificar los mensajes más compactamente en binario Se pueden usar incluso cuando se utiliza IIS como agente de activación
65/80
Canales HTTP y formateadores binarios
El siguiente Web.config registra Clock para ser activado por IIS como un objeto single-call server-activated y reemplaza el formateador SOAP por uno binario:<configuration>
<system.runtime.remoting><application>
<service><wellknown mode="SingleCall" type="Clock,
ClockServer" objectUri="Clock.rem"/></service><channels>
<channel ref="http server"><serverProviders>
<formatter ref="binary"/></serverProviders>
</channel></channels>
</application></system.runtime.remoting>
</configuration>
El cliente debe por su parte usar también un canal HTTP, que de forma programática se obtendendría:HttpClientChannel channel = new HttpClientChannel("HttpBinary", new
BinaryClientFormatterSinkProvider());ChannelServices.RegisterChannel(channel);RemotingConfiguration.RegisterWellKnownClientType(typeof(Clock),
"http://localhost/ClockServerActivatedBinaryFormatter/Clock.rem");Clock clock = new Clock();
66/80
Canales HTTP y formateadores binarios
De forma declarativa un cliente podría obtener el canal HTTP con formato binario:RemotingConfiguration.Configure("Client.exe.config");Clock clock = new Clock(); El contenido de Client.exe.config sería:<configuration> <system.runtime.remoting> <application> <client> <wellknown type="Clock, ClockServer“
url="http://localhost/ClockServerActivatedBinaryFormatter/Clock.rem" /> </client> <channels> <channel ref="http client">
<clientProviders><formatter ref="binary"/>
</clientProviders> </channel> </channels> </application> </system.runtime.remoting></configuration>
67/80
Delegates y Eventos
La infraestructura de eventos de .NET funciona con objetos remotos Un cliente conecta un manejador de eventos para eventos lanzados
por objetos remotos de igual manera que lo haría para objetos locales Lo único especial es que el cliente ha de registrar tanto un canal cliente
como servidor para recibir las callbacks De igual manera los servidores también registrarán un canal cliente
Ideal para la creación de aplicaciones peer-to-peer Un servidor de chat puede lanzar un evento cuando alguien se una al
chat El cliente registrará un manejador de eventos, y recibirá notificaciones a
través de él. Si los ejemplos de eventos no funcionan por temas de seguridad ir a
1.1 Para resolverlos mirar: http://p2p.wrox.com/topic.asp?TOPIC_ID=3077 http://www.codeproject.com/csharp/RemotingAndEvents.asp
68/80
Ejemplo Eventos Distribuidos// file: echoobj.cs// compile: csc /target:library echoobj.csusing System;namespace Echo {
public delegate void EchoEvent(object sender, EchoEventArgs e);
[Serializable]public class EchoEventArgs : EventArgs {
public EchoEventArgs(string message) {Message = message;
}public string Message;
}
public class EchoObj : MarshalByRefObject {public EchoObj() {
Console.WriteLine("EchoObj activated...");}public event EchoEvent ServerEchoEvent;public void Echo(string message) {
Console.WriteLine("received message: " + message);if (ServerEchoEvent != null) // ensure handler is registered
ServerEchoEvent(this, new EchoEventArgs(message));}
}}
69/80
Ejemplo Eventos Distribuidos
// file: echoservice.cs// compile: csc echoservice.csusing System;using System.Collections;using System.Reflection;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;
public class EchoService {public static void Main() {
// register a channel...BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;BinaryClientFormatterSinkProvider clientProv = new
BinaryClientFormatterSinkProvider();IDictionary props = new Hashtable();props["port"] = 6789;HttpChannel chan = new HttpChannel(props, clientProv,
serverProv); ChannelServices.RegisterChannel( chan );
70/80
Ejemplo Eventos Distribuidos
// register HelloObj with remoting services...Console.WriteLine("registering EchoObj as Singleton...");
Assembly ass = Assembly.Load("echoobj");
RemotingConfiguration.RegisterWellKnownServiceType(ass.GetType("Echo.EchoObj"), // remote object
type"EchoObj", // endpoint nameWellKnownObjectMode.SingeCall); // activation
mode
Console.WriteLine("waiting for remote calls...");Console.WriteLine("hit ENTER to exit...");Console.ReadLine();
}}
71/80
Ejemplo Eventos Distribuidos
// file: echoclient.cs// compile: csc /r:echoobj.dll echoclient.cs
using System;using System.Collections;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;using System.Threading;using Echo;
public class EchoHandler : MarshalByRefObject { public void Handler(object sender, EchoEventArgs e) { Console.WriteLine("echo callback: {0}", e.Message); }}
72/80
Ejemplo Eventos Distribuidos
public class EchoClient {public static void Main() {
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();props["port"] = 0;HttpChannel chan = new HttpChannel(props, clientProv, serverProv); ChannelServices.RegisterChannel( chan );EchoObj echoObjRef = (EchoObj)Activator.GetObject(
typeof(EchoObj),"http://localhost:6789/EchoObj"
);EchoHandler echoHandler = new EchoHandler();EchoEvent echoEvent = new EchoEvent(echoHandler.Handler);echoObjRef.ServerEchoEvent += echoEvent;echoObjRef.Echo("Hello!");echoObjRef.Echo("Goodbye!");Console.WriteLine("Press Enter to end...");Console.ReadLine();Console.WriteLine("Ending...");Thread.Sleep(2000); // give event time to fireechoObjRef.ServerEchoEvent -= echoEvent;
}}
73/80
Llamadas de métodos asíncronas
Las llamadas asíncronas se permiten gracias a los delegates asíncronosint count=sieve.CountPrimes(10000);delegate int CountPrimesDelegate(int max);CountPrimesDelegate del = new
CountPrimesDelegate(sieve.CountPrimes);IAsyncResult ar = del.BeginInvoke(10000, null, null);int count = del.EndInvoke(ar);if (ar.IsCompleted) {
Int count = del.EndInvoke(ar);} else {} Los métodos one-way se pueden declarar usando el atributo [OneWay]
74/80
Interoperabilidad Servicios Web/.NET Remoting
.NET Remoting y los Servicios Web se integran muy bien: Es posible escribir un servidor en .NET Remoting y
exportarlo como si se tratase de un Servicio Web Requisitos:
Hacer uso de HttpChannel Activarse como un Singleton
75/80
Ejemplo Interoperabilidad I
// calculadora.csusing System;
namespace Calculadora{
public class Calculadora : MarshalByRefObject{
public int Sumar(int Op1, int Op2){
return Op1 + Op2;}
public int Restar(int Op1, int Op2){
return Op1 - Op2;}
public int Multiplicar(int Op1, int Op2){
return Op1 * Op2;}
}}
76/80
Ejemplo Interoperabilidad II
//CalculadoraServer.csusing System;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;using System.Web.Services;namespace Calculadora {
class MyApp{
static void Main() {
HttpChannel chnl = new HttpChannel(1234);ChannelServices.RegisterChannel(chnl);RemotingConfiguration.RegisterWellKnownServiceType(
typeof(Calculadora),"Calculadora",WellKnownObjectMode.Singleton);
Console.WriteLine("Press Enter to terminate ...");Console.ReadLine();
}}
}
77/80
Ejemplo Interoperabilidad III
//ClienteCalculadora.csusing System;namespace Calculadora{
class MyApp{
public static void Main (){
CalculadoraService calc = new CalculadoraService();
int sum = calc.Sumar (2, 2);Console.WriteLine ("2 + 2 = " + sum);
}}
}
78/80
Ejemplo Interoperabilidad IV
1. csc /t:library calculadora.cs2. csc /r:calculadora.dll
CalculadoraServer.cs3. start CalculadoraServer.exe4. wsdl
http://127.0.0.1:1234/calculadora?wsdl
5. csc ClienteCalculadora.cs CalculadoraService.cs
6. ClienteCalculadora
79/80
Consideraciones de diseño
Observando la versatilidad que presenta ésta tecnología se deben evaluar ciertos aspectos de nuestro entorno: ¿Que alcance tiene nuestro entorno? ¿Internet, intranet, LAN? ¿Debemos atravesar un firewall para poder llegar a nuestros
objetos? ¿A cuantos clientes atendemos? ¿Cuanto crecerá nuestro servicio?
¿Deben viajar nuestros objetos por referencia o por valor? ¿Que cantidad promedio de información involucran las llamadas
remotas? ¿Cuanto tiempo deben vivir nuestros objetos remotos? ¿Debe ser encriptada la información que comparten estas
aplicaciones?
80/80
Conclusión
La fortaleza de .NET Remoting reside en: Capacidad para permitir la comunicación, de forma
sencilla, entre objetos de diferentes aplicaciones o procesos usando:
Diferentes protocolos de transporte Formatos de serialización Esquemas de durabilidad de los objetos Modos de creación de los objetos.