• Nu S-Au Găsit Rezultate

I. .NET Remoting 1. AppDomain

N/A
N/A
Protected

Academic year: 2022

Share "I. .NET Remoting 1. AppDomain "

Copied!
73
0
0

Text complet

(1)

I. .NET Remoting II. Servicii Web XML

I. .NET Remoting 1. AppDomain

2. Context de executie 2.1. agile context 2.2. bound context

3. Server

3.1. Activare obiecte 3.2. Distributie metadata 3.3. Configurare

3.3.1. Hard coded

3.3.2. Fisiere de configurare 3.1. Hosting

4. Client

4.1. Creare client 4.2. Configurare

4.2.1. Hard coded

4.2.2. Fisiere de configurare

II. Servicii Web XML

1. Creare serviciu

2. Consumare serviciu

(2)

.NET Remoting Ce este Remoting?

In cazul cel mai general, termenul de remoting se refera la utilizarea acelor tehnologii ce permit apelul de metode pe date partajate cu obiecte ce ruleaza in alt proces.

COM este una din aceste tehnologii.

DCOM extinde aceasta notiune pentru a include obiecte ce ruleaza in procese diferite pe masini diferite. Atat COM cat si DCOM presupun anumite configurari in registri, drepturi asupra codului executat, probleme de securitate.

Modelul .NET remoting foloseste aceste idei din COM/DCOM, dar cu o implementare complet diferita. De exemplu, informatia despre obiectul remote poate fi plasata intr-un fisier de configurare si nu in registri.

AppDomain

.NET introduce o alta notiune, cea de application domains (AppDomain).

AppDomain constituie un mediu izolat unde se executa aplicatia.

AppDomain poate fi asimilat ca fiind un subproces ce ruleaza in cadrul unui proces. Un process poate contine mai multe AppDomain-uri, iar intr-un AppDomain se poate incarca un assembly pentru executie.

In .NET frontiera unei aplicatii nu o mai constituie procesul ci AppDomain.

In acest context, .NET remoting foloseste servicii runtime pentru a invoca metode pe date partajate intre obiecte ce ruleaza in Appdomain (application domain) separate.

Programarea cu AppDomain

Clasa AppDomain

Application domains, reprezentate de obiecte AppDomain, furnizeaza izolare, descarcare appdomain si securitate pentru codul managed ce se executa.

AppDomain sunt folosite pentru a izola taskuri ce pot bloca sau termina un proces. Daca un AppDomain devine instabil, acesta poate fi descarcat din memorie fara a afecta procesul. Acest lucru e important cand un proces trebuie sa ruleze o perioada indelungata de timp fara a fi restartat. Se poate folosi AppDomain pentru a izola taskuri ce nu partajeaza date.

Daca un assembly este incarcat in AppDomain implicit, cel creat la startarea procesului, acesta nu poate fi descarcat din memorie atata timp cat procesul ruleaza.

Observatie:

Nu exista o relatie de unu-la-unu intre AppDomain si fire. Mai multe fire pot rula simultan in acelasi AppDomain. Un fir se executa intr-un singur AppDomain.

(3)

Creare AppDomain

Metoda statica CreateDomain cu urmatoarele prototipuri:

public static AppDomain CreateDomain(string friendlyName)

public static AppDomain CreateDomain(

string friendlyName,

Evidence securityInfo

) securityInfo

Type: System.Security.Policy .Evidence

Evidence that establishes the identity of the code that runs in the application domain. Pass null to use the evidence of the current application domain.

[SecurityPermissionAttribute(SecurityAction.Demand, ControlAppDomain = true)]

public static AppDomain CreateDomain(

string friendlyName,

Evidence securityInfo,

AppDomainSetup info

)

info

Type: System .AppDomainSetup

An object that contains application domain initialization information.

Creaza o instanta AppDomain cu numele specificat in parametru.

public static AppDomain CreateDomain(

string friendlyName, Evidence securityInfo, AppDomainSetup info, PermissionSet grantSet,

params StrongName[] fullTrustAssemblies )

grantSet

Type: System.Security .PermissionSet

A default permission set that is granted to all assemblies loaded into the new application domain that do not have specific grants.

fullTrustAssemblies

Type: System.Security.Policy .StrongName []

An array of strong names representing assemblies to be considered fully trusted in the new application domain.

Instantele AppDomain se folosesc pentru a incarca si executa assembly in AppDomain creat.

(4)

Metode (lista completa in MSDN)

Name Description

CreateDomain(String) Creates a new application domain with the specified name.

CreateDomain(String, Evidence) Creates a new application domain with the given name using the supplied evidence.

CreateDomain(String, Evidence, AppDomainSetup)

Creates a new application domain using the specified name, evidence, and application domain setup information.

CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName [])

Creates a new application domain using the

specified name, evidence, application domain setup information, default permission set, and array of fully trusted assemblies.

CreateInstance(String, String) Creates a new instance of the specified type defined in the specified assembly.

CreateInstance(String, String, Object [])

Creates a new instance of the specified type defined in the specified assembly. A parameter specifies an array of activation attributes.

CreateInstanceAndUnwrap(String, String)

Creates a new instance of the specified type.

Parameters specify the assembly where the type is defined, and the name of the type.

CreateInstanceFrom(String, String)

Creates a new instance of the specified type defined in the specified assembly file.

CreateInstanceFrom(String, String, Object [])

Creates a new instance of the specified type defined in the specified assembly file.

CreateInstanceFromAndUnwrap(Stri ng, String)

Creates a new instance of the specified type defined in the specified assembly file.

CreateInstanceFromAndUnwrap(Stri ng, String, Object [])

Creates a new instance of the specified type defined in the specified assembly file.

CreateObjRef

Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object. (Inherited from MarshalByRefObject.)

DoCallBack Executes the code in another application domain that is identified by the specified delegate.

ExecuteAssembly(String) Executes the assembly contained in the specified file.

ExecuteAssembly(String, String [])

Executes the assembly contained in the specified file, using the specified arguments.

ExecuteAssemblyByName(String) Executes an assembly given its display name.

ExecuteAssemblyByName(AssemblyNa me, String [])

Executes the assembly given an AssemblyName, using the specified arguments.

ExecuteAssemblyByName(String,

String []) Executes the assembly given its display name,

(5)

using the specified arguments.

GetAssemblies Gets the assemblies that have been loaded into the execution context of this application domain.

GetData Gets the value stored in the current application domain for the specified name.

IsFinalizingForUnload

Indicates whether this application domain is unloading, and the objects it contains are being finalized by the common language runtime.

Load(AssemblyName) Loads an Assembly given its AssemblyName.

Load(String) Loads an Assembly given its display name.

SetData(String, Object) Assigns the specified value to the specified application domain property.

SetData(String, Object, IPermission)

Assigns the specified value to the specified application domain property, with a specified permission to demand of the caller when the property is retrieved.

Unload Unloads the specified application domain.

Cand un AppDomain nu mai este folosit, poate fi descarcat din memorie (Unload).

Dintre evenimentele implementate mentionam:

Name Description

AssemblyLoad Occurs when an assembly is loaded.

AssemblyResolve Occurs when the resolution of an assembly fails.

DomainUnload Occurs when an AppDomain is about to be unloaded.

ProcessExit Occurs when the default application domain's parent process exits.

Exemplu complet. Se creaza un AppDomain ce va fi executat. Incarcarea si lansarea in executie se face din AppDomain implicit (cel creat la incarcarea procesului).

namespace AppDomSecundar {

// Cod ce va fi rulat intr-un alt AppDomain // Este un proiect de tip Console - CUI public class MathClient

{

static void Main(string[] args) {

Console.WriteLine();

// Referinta la AppDomain

AppDomain myDomain = AppDomain.CurrentDomain;

// Cateva informatii de afisat...

Console.WriteLine(

"Informatii despre AppDomain MathClient ...");

Console.WriteLine(" Name = {0}", myDomain.FriendlyName);

Console.WriteLine(" Director = {0}", myDomain.BaseDirectory);

(6)

Console.WriteLine();

// Executam metodele Add si Subtract din clasa SimpleMath Console.WriteLine(" 5 + 3 = {0}", SimpleMath.Add(5, 3));

Console.WriteLine(" 5 - 3 = {0}", SimpleMath.Subtract(5, 3));

// Definim proprietatea "add" pe care o vom interoga // in AppDomain apelant

myDomain.SetData("add", SimpleMath.Add(5, 3).ToString());

} }

// Tipul de data folosit in AppDomain public class SimpleMath

{

public static int Add(int x, int y) {

return x + y;

}

public static int Subtract(int x, int y) {

return x -y;

} } }

Observatie

Dupa compilarea si link editarea codului de mai sus se creaza un assembly cu numele

AppDomSecundar.exe. Acest assembly va fi incarcat si executat intr-un AppDomain. Vedeti codul de mai jos.

// AppDomain principal : va crea un AppDomain // Proiect de tip Console - CUI

class AppDomPrincipal {

static void Main(string[] args) {

// Referinta la AppDomain curent

AppDomain myDomain = AppDomain.CurrentDomain;

// Cateva informatii

Console.WriteLine("AppDomain principal ...");

Console.WriteLine(" Hash Code = {0}", myDomain.GetHashCode());

Console.WriteLine(" Name = {0}", myDomain.FriendlyName);

Console.WriteLine(" Director AppDomain principal = {0}", myDomain.BaseDirectory);

// Creaza un nou AppDomain cu numele "MathClient"

AppDomain mathDomain = AppDomain.CreateDomain("MathClient");

// Execut AppDomSecundar.exe

// Fisierul AppDomSecundar.exe este in acelasi director // ca si aplicatia curenta.

mathDomain.ExecuteAssembly("AppDomSecundar.exe");

// Obtin date din AppDomain "MathClient"

object obj = mathDomain.GetData("add");

(7)

Console.WriteLine("In AppDomain principal... " +

"Data (5 + 3 = {0})", obj.ToString());

Console.ReadLine();

}

Rezultatul este:

AppDomain principal ...

Hash Code = 12547953

Name = AppDomPrincipal.vshost.exe Director AppDomain principal =

D:\ExeNET\ObjRefExemplu\AppDomPrincipal\bin\Debug\

Informatii despre AppDomain MathClient ...

Name = MathClient

Director = D:\ExeNET\ObjRefExemplu\AppDomPrincipal\bin\Debug\

5 + 3 = 8 5 - 3 = 2

In AppDomain principal... Data (5 + 3 = 8)

C

ontext AppDomain.

Context agile. Context bound.

Contextele furnizeaza urmatoarele:

• un mediu ce consta din o multime de proprietati, partajate de toate obiectele din acelasi context;

• runtime-ul poate aplica pre si post-procesari pentru toate apelurile metodelor din afara contextului;

• “host” pentru obiectele cu cerinte runtime similare (sincronizare, afinitate la fir sau activare just-in-time ).

Un AppDomain poate contine mai multe contexte, dintre care unul este contextul implicit.

Cand runtime-ul creaza un obiect, acesta investigheaza cerintele obiectului si-l plaseaza intr-un context compatibil. Daca acest context nu exista atunci runtime-ul il creaza. Majoritatea obiectelor sunt create in contextul implicit.

Obiectele fara cerinte de context sunt numite "context agile". Aceste obiecte pot fi accesate in mod direct de oriunde din interiorul unui application domain.

Obiectele ce au cerinte de context sunt numite “context bound” si trebuie sa fie derivate din clasa ContextBoundObject.

Pentru mai multe informatii despre ContextBoundObject consultati MSDN.

Codul ce se executa in afara unui context nu va retine niciodata o referinta directa la obiectele continute intr-un “context bound”.

Accesul in afara limitelor contextului este realizat printr-un proxy construit de runtime, proxy ce imita obiectul actual.

(8)

Proxy permite runtime-ul de a intercepata apleuri in afara contextului si sa aplice cerintele de pre si post-procesare.

Exemplu cu context: Syncronization

Putem defini pentru un tip cerinte asupra unui anumit context folosind atributele. Un exemplu de atribut de context este clasa SynchronizationAttribute. Cand se aplica acest atribut la o clasa, runtime-ul asigura ca numai un fir la un moment dat de timp poate accesa orice instanta a clasei.

Pentru a realiza acest lucru, runtime-ul va crea obiectul intr-un anumit context si va intercepta orice cerinta de apel venita din afara contextului. Daca un fir se executa in cadrul unui context, runtime-ul forteaza toate apelurile din alte fire sa astepte pana cand firul respectiv se termina.

Exemplu

namespace SimpleContext {

using System.Runtime.Remoting.Contexts;

// O clasa "context bound"

[Synchronization]

public class MyContextBoundClass : ContextBoundObject { }

// Clasa in context “agile”

public class MyAgileClass { }

}

Test pentru cele doua clase namespace SimpleContext {

using System;

using System.Runtime.Remoting;

// RemotingServices class class SimpleContextMain

{

static void Main(string[] args) {

MyContextBoundClass myBound = new MyContextBoundClass();

MyAgileClass myAgile = new MyAgileClass();

// Are they in or out of context?

Console.WriteLine("\nIs myBound out of context? {0}", RemotingServices.IsObjectOutOfContext(myBound));

Console.WriteLine("Is myAgile out of context? {0}", RemotingServices.IsObjectOutOfContext(myAgile));

// Direct reference or proxy?

Console.WriteLine("\nIs myBound a proxy? {0}", RemotingServices.IsTransparentProxy(myBound));

(9)

Console.WriteLine("Is myAgile a proxy? {0}", RemotingServices.IsTransparentProxy(myAgile));

Console.ReadLine();

} }

} // namespace SimpleContext

Rezultatul este:

myBound este in afara contextului si este un proxy;

myAgile nu este in afara contextului si nu este un proxy.

Regasirea informatiei despre context : Thread.CurrentContext

Informatia despre context este furnizata de proprietatea Thread.CurrentContext. Aceasta proprietate returneaza un obiect Context, pe care-l putem folosi pentru a obtine informatii despre context.

Clasa Context contine o proprietate numita ContextProperties ce returneaza o colectie de IContextProperties.

Exemplu

public class Diagnostics {

// Displays the context id and properties for the given context.

public static void DisplayContextInfo() {

Context ctx = Thread.CurrentContext;

Console.WriteLine(" Properties for context id: {0}", ctx.ContextID);

foreach(IContextProperty ctxProp in ctx.ContextProperties) {

Console.WriteLine(" {0}", ctxProp.Name);

} } }

“Pasarea” obiectelor (Marshaling Objects)

Exista doua posibilitati:

pasarea prin valoare (MBV - Marshal By Value).

pasarea prin referinta (MBR - Marshal By Reference).

Conceptual aceste tehnici de marshaling sunt similare notiunii de pasarea parametrilor unei metode prin valoare sau referinta. Deosebirea principala la MBR ; se transmite un proxy, nu se transmite o referinta directa la obiect. Pentru MBV obiectele trebuie sa poata fi serializate.

De exemplu, avem posibilitatea de a invoca urmatoarea metoda pe un obiect ce ruleaza intr-un appdomain separat:

public SomeClass GetAnObject()

(10)

{ return new SomeClass();}

Daca SomeClass a fost definita ca tip MBV, atunci metoda returneaza o copie a obiectului, in caz contrar, apelul metodei de mai sus returneaza un proxy. Fiecare tehnica este valida.

MBV

Cand folosim MBV, runtime creaza o copie a obiectului remote in appdomain-ul clientului prin mecanisme de serializare (serializare pe partea serverului si deserializare pe partea clientului).

Este necesar ca obiectul sa poata fi serializat.

Runtime va pasa obiectul prin MBV daca clasa are atributul Serializable. [Serializable()]

public class MyMBVClass { // Implementare clasa }

MBR - clasa MarshalByRefObject

Obiectele MBR raman in appdomain unde au fost create. Clientii invoca metode pe obiectele MBR printr-un proxy ce redirecteaza apelurile (obiectul este intr-un AppDomain iar clientul este in alt AppDomain).

Observatie

Obiectele MBR trebuiesc sa fie derivate direct sau indirect din MarshalByRefObject. public class MyMBRClass : MarshalByRefObject

{

// Implementare clasa }

In fapt toate tipurile deriveaza din ContextBoundObject care la randul lor sunt derivate din MarshalByRefObject.

Toate tipurile “context bound” sunt tipuri MBR.

Tipurile MBR ne permit sa distribuim procesarea.

Exemplu

// Un tip MBV (nu e derivat din MarshalByRefObject) // Este serializabil.

[Serializable]

public class CustomerData {

private string mFirstName;

private string mLastName;

private string mEmail;

// ...

}

// Un tip MBR ce contine o metoda ce returneaza CustomerData public class CustomerService : MarshalByRefObject

{

(11)

public CustomerData GetCustomerByEmail(string email) {

CustomerData custData = new CustomerData();

// cod ...

// return prin valoare return custData;

} }

Exemplu. Cum se foloseste acest tip.

class ClientMain {

static void Main(string[] args) {

// Deoarece CustomerService este MBR, se returneaza // un proxy la obiectul remote.

CustomerService custService = new CustomerService();

// CustomerData este MBV, deci se returneaza // o copie a obiectului remote

CustomerData custData =

custService.GetCustomerByEmail("[email protected]");

// cod ...

} }

Metode statice si alte detalii despre remoting

In cele mai multe cazuri, metodele unui obiect MBR se executa in interiorul “remote appdomain”.

Urmatoarele exceptii trebuiesc luate in considerare:

Membrii statici. Metodele statice se executa totdeauna in appdomain-ul apelantului.

Campurile statice sunt accesate direct din memorie (nu prin proprietati) si nu pot fi accesate direct din afara appdomain original. Campurile statice pot fi accesate de metoade ale instantei deoarece acestea se executa in “remote appdomain”.

Campuri ale instantei. Daca obiectul MBR expune campuri publice ale instantei, atunci proxy generat in mod automat de runtime defineste proprietatile (se genereaza set si get) pentru accesul campurilor pe obiectul remote. In general nu este recomandat sa se expuna campuri publice ale instantei pentru ca violeaza principiul de incapsulare al obiectului.

Metodele System.Object. Pentru a creste performanta, apelurile la metodele mostenite din System.Object sunt executate in appdomain-ul apelantului. Daca obiectul MBR suprascrie metodele Equals sau ToString, atunci acestea vor fi executate in appdomain al obiectului remote.

(12)

Sintetizare Marshaling si context agile

Table 3-1: Summary of Marshaling and Agility Options Type Base Class and Attributes Description

Not Remotable

Not derived from

MarshalByRefObject. Not decorated with Serializable.

This type cannot be marshaled out of an application domain. It is agile within a domain, so code in another context holds a direct reference. Use for types that must never be accessed from another domain.

Marshal By Value

Not derived from MarshalByRefObject.

Serializable.

When this type is marshaled out of an application domain, it is serialized, transported across the domain boundary, and deserialized in the client domain.

However, it is agile within a domain, so code in another context holds a direct reference. Use for types that primarily encapsulate data and have no methods that need to execute within the server domain.

Marshal By Reference

MarshalByRefObject. No specific attribute

requirements.

When this type is marshaled out of an application domain, the client domain builds a proxy to the remote object. It is agile within the domain, so code in

another context holds a direct reference. Use for types that must execute within the application domain where they were created.

Context Bound

ContextBoundObject.

Decorate with any context attribute.

When this type is marshaled out of an application domain or a context, the client code builds a proxy to the object. Use for types that require special runtime services such as synchronization.

.NET Remote Framework. Generalitati.

Infrastructura remoting consta din:

Proxy.

Canale de comunicatie.

Mesaje.

Proxy sunt obiecte locale ce impersoneaza obiectul remote. Proxy expune exact aceleasi metode si proprietati ca si obiectul remote. Oricum, implementarea unui proxy pentru o metoda data face apel la obiectul channel. Proxy creaza impresia ca obiectul remote este in acelasi proces cu clientul.

Obiectul channel reprezinta o conexiune la aplicatia remote. Fiecare obiect channel contine un obiect formatter care converteste apelul metodei intr-un mesaj cu un format cunoscut.

Mesajul este trimis la server ce asculta pe un anumit canal de comunicatie. Folosind obiectul formatter al canalului se deserializeaza mesajul si se trimite la un obiect intern numit StackBuilder. Acest obiect converteste mesajul intr-un apel de metoda si apeleaza metoda pe obiectul remote.

(13)

Urmatoarele figuri evidentiaza modul de lucru.

Masina X. Client din AppDomain 1 nu are nevoie de proxy pentru a accesa obiectul remote.

Masina Y

Client Proxy

AppDomain

Serviciu Proxy Client

Client Proxy

AppDomain 1

AppDomain 2

(14)

Observatie

Procesul ce contine obiectul remote (identificat aici prin Serviciu pe masina X) nu e obligatoriu sa contina « Client ».

Obiecte Well-Known vs. Obiecte Client-Activated

Un appdomain poate expune tipuri MBR ca fiind obiecte well-known (server activated) sau obiecte client-activated.

Principala diferenta intre aceste obiecte o constituie modul cum sunt create si cum e gestionat timpul de viata al acestora.

Obiecte well-known

Pentru obiectele well-known, atribuim un nume unic si cunoscut, nume pe care clientul il paseaza runtime-ului pentru a se conecta la server. Serverul raspunde prin instantierea obiectului folosind constructorul implicit. In ceea ce priveste timpul de viata, un obiect well-known poate fi partajat de toti clientii si persista intre cererile clientilor (numite Singleton mode), sau pot exista in cadrul unui singur apel (numit SingleCall mode).

Obiectele wel-known sunt adesea cunoscute si sub numele de obiecte activate de server.

Obiecte client-activated

Un obiect client-activated permite clientului de a-l activa folosind orice ctor, nu numai ctor implicit. Timpul de viata al unui obiect client-activated este dictat de Leasing Distributed Garbage Collector, ce atribuie fiecarui asemenea obiect o anumita cuanta de timp (lease).

Din nou despre proxy

.NET runtime foloseste doua tipuri de proxy: proxy transparent si proxy real.

Proxy transparent – nu poate fi extins

Cand un client foloseste apeluri API runtime cum ar fi Activator.GetObject pentru a se conecta la un obiect remote, runtime returneaza clientului un proxy transparent. Acest proxy furnizeaza un nivel de interceptare pe partea clientului pentru runtime, permitand astfel verificarea numarului corect de parametri pentru o metoda precum si tipurile acestora. De asemenea acest proxy permite runtime-ului sa determine daca obiectul este rulat local sau la distanta.

Observatie

In cazul cand obiectul este rulat local, runtime va invoca direct metoda.

Un proxy transparent impacheteaza apelul metodei si toti parametri intr-un obiect IMessage si il paseaza cu ajutorul metodei Invoke proxy-ului real (RealProxy).

(15)

Proxy transparent este creat in mod dinamic de runtime si nu poate fi extins pentru a crea proxy personalizate.

Observatie

Proxy transparent este continut intr-un proxy real.

In fapt, proxy real furnizeaza un punct de interceptie pentru dezvoltator pentru a insera cod pentru procesare in timpul unui apel remote.

Proxy transparent apeleaza metoda Invoke a proxy-ului real.

Implementarea implicita a metodei Invoke face ca aceasta sa paseze obiectul IMessage obiectului channel.

Generarea dinamica a proxy-ului Clasa ObjRef

Generarea dinamica a proxy-ului are la baza reflection si clasa ObjRef.

ObjRef memoreaza informatiile necesare pentru a genera un proxy, folosit in comunicarea cu un obiect remote.

In MSDN ObjRef este definita astfel:

[SerializableAttribute]

[ComVisibleAttribute(true)]

[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]

[SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.Infrastructure)]

public class ObjRef : IObjectReference, ISerializable

Un ObjRef este o reprezentare serializabila a unui obiect ce extinde MarshalByRefObject. Un ObjRef este folosit pentru a transfera o referinta a obiectului intre frontierele AppDomain. Crearea unui ObjRef pentru un obiect este cunoscuta ca operatie numita marshaling.

ObjRef contine informatii ce descriu Type si clasa obiectului ce va fi transmis, locatia sa exacta, informatii despre comunicare.

Dupa ce o clasa - ce a implementat MarshalByRefObject - este transmisa (marshaled), obiectul ObjRef ce o reprezinta este transferat prin canalul de comunicatie in alt AppDomain, posibil in alt proces sau alt calculator.

Cand ObjRef este deserializat (vezi serializarea XML si SOAP) in AppDomain destinatie, se va crea un proxy transparent pentru obiectul remote MBR. Operatia este cunoscuta sub numele de unmarshaling.

Sa consideram urmatorul exemplu

(16)

public class Customer : MarshalByRefObject {

// Implementare ...

}

public class CustomerService : MarshalByRefObject {

public Customer CreateCustomer() {

return new Customer();

} }

Avem doua tipuri drivate din MarshalByRefObject, deci instantele acestor tipuri vor fi transmise prin referinta, MBR.

Clasa CustomerService expune o metoda ce creaza si retureaza un obiect Customer. Presupunand ca aplicatia server expune tipul CustomerService ca un obiect well-known, urmatorul cod din client poate fi folosit pentru a crea un proxy la obiectul remote:

CustomerService custSvc = (CustomerService) Activator.GetObject(...);

Metoda GetObject accepta argumente ce specifica tipul si locatia obiectului remote dat.

Cu aceasta informatie, runtime din client va folosi reflection pe obiectul remote pentru a obtine metodele publice si semnatura acestora in vederea crearii unui proxy transparent.

Name Description

Activator.GetObject (Type, String)

Creaza un proxy pentru obiectul well-known indicat de tipul specificat si URL.

Activator.GetObject (Type, String, Object)

Creaza un proxy pentru obiectul well-known indicat de tipul specificat, URL si canalul de date.

Cum are acces RT din client la tipul remote?

Raspuns : Distributie metadata

Pentru rezolvarea acestei probleme (distributie metadata) s-au imaginat cateva scenarii.

Cel mai simplu este distribuirea pe partea clientului a assembly-ului ce contine tipul. Acest lucru nu este totdeauna de dorit (cod proprietar sau cod secret, etc.). Vezi scenariile de la distributia metadatei .

Oricum codul din client nu poate fi compilat daca nu exista informatia despre tip.

Apelul Activator.GetObject nu implica trafic in retea, se executa local.

In fapt nici un apel nu este facut la server pana cand nu se invoca o metoda din server.

(17)

Generare proxy si ObjRef

Fie urmatorul cod (clasele au fost definite mai sus):

Customer cust = custService.CreateCustomer();

Aceasta metoda returneaza o referinta la un obiect Customer. Deci RT de pe partea clientului trebuie sa genereze un proxy pentru acest obiect dar fara a apela Activator.GetObject. Aici intervine serverul care nu va returna o referinta la obiectul Customer, ci va returna un ObjRef.

ObjRef este un obiect CLR ce contine informatii privitoare la tipul remoting:

• numele tipului obiectului remote, calificat complet, incluzand informatia despre assembly;

• numele tipurilor tuturor obiectelor remote ale clasei de baza;

• numele tipurilor tuturor interfetelor implementate de obiectul remote;

• obiectul URI si informatii privitoare la canalul inregistrat pe server.

ObjRef este transmis prin valoare, deci acesta este serializat si returnat clientului in locul obiectului Customer. RT din client foloseste aceasta informatie continuta in ObjRef pentru a genera proxy.

Un ObjRef este creat si serializat ori de cate ori un obiect MBR este pasat intr-o metoda remote sau returnat dintr-o metoda remote, fie ca valoare de retur sau un parametru out.

// undeva in cod ...

Customer cust = new Customer();

remoteObject.SomeMethod(cust);

Daca remoteObject este un alt obiect remote, atunci apelul SomeMethod trimite un obiect Customer in obiectul remote. Deoarece Customer este de tip MBR se creaza un ObjRef se serializeaza si se trimite catre appdomain remote unde este utilizat pentru a genera un proxy.

Observatie

Obiectul Customer folosit mai sus nu se incadreaza nici in well-known nici in client-activated (nu este creat nici de client, nici de server, ci de o metoda). Un asemenea obiect se comporta ca un obiect client-activated.

Channels si Formatters

Channels reprezinta o abstractizare pentru remoting framework, abstractizare ce ascunde complexitatile protocolului utilizat pentru comunicare intre client si server. Obiectul channel este responsabil pentru transportul fiecarui apel de metoda de la client la server si a valorilor returnate de server catre client.

Fiecare channel contine un obiect formatter ce se ocupa de serializare.

CLR furnizeaza clase de baza si interfete ce pot fi utilizate pentru a dezvolta channel si formatter personalizati.

(18)

HTTP Channel vs. TCP Channel

TCP channel (reprezentat de clasa TcpChannel) furnizeaza conectivitate folosind protocolul TCP/IP. Implicit acest channel foloseste BinaryFormatter pentru a converti apelurile intr-un format binar proprietar. Acest TCP channel necesita stabilirea unui port unic pe masina server.

Are probleme cu firewall-ul.

HTTP channel (reprezentat de clasa HttpChannel) foloseste protocolul HTTP. Acest channel foloseste SoapFormatter pentru a converti apelurile de metoda intr-un format SOAP.

Cantitatea de informatii de transferat pe retea este mare in acest caz.

Deoarece HTTP lucreaza cu portul 80, de obicei firewall-ul nu blocheaza acest port pentru a avea conexiune la internet. In concluzie lucreaza bine cu firewall-ul.

Inregistrarea canalelor – clasa ChannelServices

Atat serverul cat si clientul trebuie sa aleaga un canal cu care sa se inregistreze la runtime.

Aceasta inregistrare poate fi facuta folosind clasa ChannelServices.

ChannelServices : furnizeaza metode statice folosite in inregistrarea canalului, rezolutie si descoperirea URL.

Inregistrarea unui canal implica urmatoarele:

1. stabilirea unui endpoint. Un endpoint descrie locatia aplicatiei in cadrul unei retele.

Endpoint consta din IP masinii si un numar de port (10.77.1.12:13000).

2. inregistrarea unui channel in server, ceea ce face ca RT sa stabileasca un fir “listener” ce se executa in acelasi appdomain. Scopul acestui fir este de a asculta pe endpoint pentru apeluri la metode remote si a trimite rezultate inapoi la client.

RT permite numai un channel pentru un tip de data sa fie inregistrat la nivel de appdomain.

Intr-un appdomain putem avea HTTP channel cat si TCP channel.

Clasa ChannelServices

Clasa furnizeaza metode statice pentru a inregistra canale de comunicatie.

Canalele de comunicatie trebuie sa expuna intefata IChannel ce defineste proprietatile ChannelName si ChannelPriority.

Metoda RegisterChannel inregistreaza canalele de comunicatie.

Canalele pot fi configurate si cu ajutorul fisierelor de configurare.

Fisierul de configurare

Structura elementului din fisierul de configurare este urmatoarea:

<channel

id="channelID"

type="ChannelType, ChannelAssembly"

displayName="displayName"

customChannelProperty="customChannelValue"

<!-- Available only to client configurations -->

delayLoadAsClientChannel="true|false"

(19)

/>

Vezi MSDN

Attributes

Attribute Description

customChannelProperty

Optional attribute.

Indicates a supported custom channel property. You can specify any number of channel properties that channels might support. A custom channel property would be specified with an

attribute/value pair. For example:

<channel id="CustomChannel"

type="Namespace.CustomChannel, CustomChannels"

customProperty="PropertyValue"/>

delayLoadAsClientChannel

Optional attribute.

Indicates whether this channel should be loaded if the client does not register a channel for the application. This value is a Boolean, and only affects client behavior. The value true indicates that .NET Framework remoting should test this channel at run time to see whether it supports a client connection using the particular protocol scheme specified in the remote activation URL. If the value is not present, the default value is false.

displayName

Optional attribute.

Used by the .NET Framework Configuration Tool to create a list of channels this application uses. The .NET Framework remoting system does not use this attribute.

Id

Required attribute.

Provides the string that applications use to identify the channel at registration. To reference this channel template, specify this attribute as the value of the ref attribute in the instance channel element.

Child Elements

Element Description

<serverProviders>

Contains sink providers for sinks that are to be inserted into the server-side channel sink call chain. If specified, these completely override the defaults for the channel. Can occur once in the <channel> template element.

<clientProviders>

Contains sink providers for sinks that are to be inserted into the client-side channel sink call chain. If specified, these completely override the defaults for the channel. Can occur once in the <channel> template element.

(20)

Parent Elements

Element Description

Channels

Contains channel templates that the application uses to communicate with remote objects. Channels declared under this element are available for referencing anywhere a channel is registered.

Configuration The root element in every configuration file used by the common language runtime and .NET Framework applications.

system.runtime.remoting Specifies the root element for the ASP.NET configuration section.

<channel

type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting, ...."

id="httpbinary"

>

ChannelServices.

Metoda RegisterChannel(IChannel, Boolean)

Inregistreaza un canal de comunicatie.

Namespace: System.Runtime.Remoting.Channels

[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.RemotingConfiguration)]

public static void RegisterChannel(

IChannel chnl,

bool ensureSecurity

)

Parameters

chnl

Type: System.Runtime.Remoting.Channels. IChannel The channel to register.

ensureSecurity

Type: System. Boolean

true ensures that security is enabled; otherwise false. Setting the value to false does not effect the security setting on the TCP or IPC channel.

Exceptions

Exception Condition

ArgumentNullException The chnl parameter is null.

RemotingException The channel has already been registered.

SecurityException At least one of the callers higher in the call stack does not have permission to configure remoting types and channels.

NotSupportedException Not supported in Windows 98 for TcpServerChannel and on all

(21)

platforms for HttpServerChannel. Host the service using Internet Information Services (IIS) if you require a secure HTTP channel.

Remarks

The RegisterChannel(IChannel, Boolean) method receives the IChannel interface from a channel object. The channel's ChannelName must be unique, or the channel must be anonymous. A channel is anonymous if the IChannel. ChannelName is set to either null or Empty by using the name configuration property.

You cannot register two channels with the same name in a AppDomain. By default, the name of a HttpChannel is "http" and the name of a TcpChannel is "tcp". Therefore, if you want to register two channels of the same type, you must specify a different name for one of them through configuration properties.

If the ensureSecurity parameter is set to true, the remoting system determines whether the channel implements ISecurableChannel, and if so, enables encryption and digital signatures. An exception is thrown if the channel does not implement ISecurableChannel.

Exemplu

// Cod in server

// Creare canal specificand numarul de port HttpChannel channel = new HttpChannel(8080);

// Inregistrare canal cu serviciile runtime remoting ChannelServices.RegisterChannel(channel, false);

// Cod in client

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel, false);

// Obtin proxy la obiectul remote

Object remoteObj = Activator.GetObject(

typeof(MathLibrary.Calculator),

"http://localhost:8080/CalculatorURI.soap");

Implementarea obiectelor Well-Known

Vom incepe prin a implemeta o aplicatie server ce expune obiecte well-known (WKO) pe care un client le poate utiliza.

Construirea serverului

Un nume pentru obiectele WKO are formatul dat de URL, exact ca adresa un site Web.

(22)

Serviciul .NET remoting furnizeaza metode ce permit inregistrarea unui tip ca WKO obiect si atribuirea unui URL pe care clientii pot sa-l foloseasca pentru a a accesa tipul.

Etapele pentru construirea unui server sunt:

1. Implementarea unei clase / unor clase ce deriva din MarshalByRefObject. Se creaza un proiect de tip ClassLibrary.

2. Adaugarea unei referinte la asssembly System.Runtime.Remoting.dll.

3. Alegerea unui canal (TCP sau HTTP), si inregistrarea acestuia folosind metoda ChannelServices.RegisterChannel.

4. Inregistrarea clasei ca un obiect WKO folosind metoda RemotingConfiguration.RegisterWellKnownServiceType.

5. Tinerea serverului in viata pentru a astepta cereri de la clienti.

Etapa 1. Definim tipul (proiect de tip library) namespace MathLibrary

{

/// <summary>

/// Tipurile ce vor fi expuse prin remoting

/// Clasa contine doua metode: Add si Divide ce vor /// fi executate in procesul serverului

/// </summary>

public class Calculator: MarshalByRefObject {

public float Add(float x, float y) {

return x + y;

}

public float Divide(float x, float y) {

if (y != 0)

return x / y;

else

throw new RemotingException(

"Impartirea prin zero este imposibila");

} } }

Etapele 2-5. Cream o aplicatie consola, numita MathServer si inregistram clasa Calculator ca un obiect WKO:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net.Configuration;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels; // Channel Services // Adaugam referinta la System.Runtime.Remoting

// Project->Add Reference -> Net -> ...

// si selectam System.Runtime.Remoting

(23)

using System.Runtime.Remoting.Channels.Http;

// adaugam referinta la MathLibrary - proiectul creat mai sus // Project->Add Reference -> Projects -> ...

using MathLibrary;

namespace Server {

/// <summary>

/// Host pentru obiectul remote: MathLibrary.Calculator /// Aplicatie tip consola

/// </summary>

class ServerCUI {

static void Main(string[] args) {

//

// Configurare protocol si port "Hard coded"

//

// Creare canal specificand numarul de port HttpChannel channel = new HttpChannel(8080);

// Inregistrare canal cu serviciile runtime remoting //

ChannelServices.RegisterChannel(channel, false);

// Inregistram tipul ca fiind well-known si Singleton RemotingConfiguration.RegisterWellKnownServiceType(

typeof(MathLibrary.Calculator),

// Tipul pe care-l inregistram in server "CalculatorURI.soap",

// Numele sub care este inregistrat WellKnownObjectMode.Singleton

// Well-known: SingleCall sau Singleton );

/*

* Pentru a folosi fisier de configurare comentati liniile de cod de mai sus

* si decomentati linia urmatoare de cod:

* */

// RemotingConfiguration.Configure(

// "ServerConfigurationFile.config", // false);

// Serverul ruleaza si asteapta clienti...

Console.WriteLine(

"Server lansat in executie...\n Press Enter to end" );

Console.ReadLine();

} } }

La apelul metodei RemotingConfiguration.RegisterWellKnownServiceType incepe lucrul adevarat (de aici incepe executia codului). Cu acest apel inregistram Calculator ca un tip ce

(24)

poate fi folosit la distanta. De asemenea ii atribuim un obiect URI, “CalculatorURI.soap”, ce devine parte a numelui pe care clientul il foloseste pentru a se referi la obiect. In final specificam ca RT ar trebui sa activeze obiectul in Singleton mode.

Construirea clientului

Urmatorul pas este de a construi o aplicatie client ce va folosi tipul remote Calculator.

Inainte de a face acest lucru trebuie sa stim urmatoarele:

1. Numele masinii unde este aplicatia server.

2. Tipul canalului pe care-l foloseste serverul pentru a expune obiectele.

3. Numarul de port pe care asculta serverul.

4. URI-ul atribuit obiectului remote.

5. Metadata obiectelor remote expuse de server.

Vom combina toate aceste informatii intr-un URL ce va identifica obiectul remote.

http://localhost:8080/CalculatorURI.Soap

Client - etapa 1. Construim metadata pentru client (versiunea “stub”).

E un proiect de tip ClassLibrary ce va avea in final acelasi namespace si acelasi tip implementat astfel:

// Tip distribuit pe client using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

//

// Proiect tip: ClassLibrary

// Am modificat numele fisierului rezultat in MathLibrary.dll // Project -> Properties -> Application ... Assembly si Namespace //

// Trebuie sa aiba acelasi nume cu cel distribuit in ServerCUI // Trebuie sa fie acelasi namespace

namespace MathLibrary {

// Acest tip va fi distribuit pe client

// Project -> Add Reference ... urmat de using MathLibrary public class Calculator: MarshalByRefObject

{

public float Add(float x, float y) {

throw new InvalidOperationException(

"Metoda nu poate fi executata local!");

}

public float Divide(float x, float y) {

throw new InvalidOperationException(

"Metoda nu poate fi executata local!");

}

(25)

} }

In general etapele pentru crearea clientului sunt:

1. Adaugarea unei referinte la System.Remoting.Runtime.Remoting.dll.

2. Adaugarea unei referinte la assembly ce contine metadata pentru tipul remote, in acest caz MathLibrary.dll.

3. Inregistrarea unui obiect channel ce foloseste acelasi tip de canal ca si serverul.

4. Apelul metodei Activator.GetObject, in care pasam URL, pentru a regasi un proxy la obiectul remote.

5. Cast proxy la tipul corect si folosirea acestuia atata timp cat este un obiect actual.

Client – etapa 2. Adaugare referinte necesare la proiect, constructie si inregistrare canal de comunicatie, utilizare obiecte expuse de server.

Urmeaza codul:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.Remoting;

using System.Net.Configuration;

using System.Runtime.Remoting.Services;

// Add reference to System.Runtime.Remoting using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

// Add refrence to MathLibraryMetadataStub using MathLibrary;

namespace Client_MetadataStub {

class Client_MetadataStub {

static void Main(string[] args) {

//

// Configurare client "Hard coded"

// Construire canal de comunicatie

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel, false);

// Obtin proxy la obiectul remote Object remoteObj = Activator.GetObject(

typeof(MathLibrary.Calculator),

"http://localhost:8080/CalculatorURI.soap");

// Cast tip returnat la tipul Calculator Calculator math = (Calculator)remoteObj;

// Utilizare obiect remote

(26)

float fadd = math.Add(15.2f, 3.7f);

Console.WriteLine("math.Add(15.2f, 3.7f) = {0}", fadd);

try {

float fdiv = math.Divide(12.0f, 0.0f);

Console.WriteLine("math.Divide(12.0f, 0.0f) = {0}", fdiv);

}

catch (Exception ic) {

Console.WriteLine(

"Eroare : \n(message) {0} \n(stack trace) {1} \n(inner) {2}", ic.Message, ic.StackTrace, ic.InnerException);

}

Console.Write("Press enter to end");

Console.ReadLine();

} } }

Explicatii

Ca si mai inainte, mai intai cream un obiect channel HTTP.

Regasim un proxy ce reprezinta obiectul remote. Pentru acest lucru folosim metoda Activator.GetObject. In final facem conversia (cast) proxy-ului returnat la tipul Calculator. Din acest moment putem starta proiectul Client.

Cand scriem codul client pentru a activa obiectul remote, putem proceda in mai multe moduri.

Ceea ce difera, este doar sintaxa, rezultatul final fiind acelasi.

Putem folosi metoda statica Connect din clasa RemotingServices: Calculator math = (Calculator)RemotingServices.Connect(

typeof(MathLibrary.Calculator),

http://localhost:8080/CalculatorURI.soap);

O alta optiune este de a utiliza metoda RegisterWellKnownClientType furnizata de clasa RemotingConfiguration. Chiar daca aceasta metoda nu creaza un proxy, il putem crea mai tarziu folosind new.

RemotingConfiguration.RegisterWellKnownClientType(

typeof(MathLibrary.Calculator),

"http://localhost:8080/CalculatorURI.soap"

);

Calculator math = new Calculator();

Observatie

Toate tehnicile expuse pina acum au ceva in comun: nu exista activitate in retea pina cand nu este activata o metoda pe un obiect remote.

(27)

Singleton vs. SingleCall

In exemplul anterior am creat un obiect in Singleton mode, deci acest obiect poate deservi mai multi clienti. Daca obiectul a fost supus colectarii si un alt client cere executia unei metode pe obiect, atunci obiectul va fi recreat.

Sincronizare

Daca clienti multipli, acceseaza un obiect Singleton in acelasi timp, fiecare cerere se va executa pe un fir separat. RT .NET are preconstruit o facilitate de pooling thread ce dedica fire in mod eficient pentru aceste cereri. Din acest motiv trebuie sa asiguram sincronizarea la accesul si modificarea campurilor de instanta ale obiectului (vezi sincronizare - lock in C#).

Modul Singleton este de folos cand obiectul contine anumite stari sau resurse ce ar trebui partajate de toti clientii. In mod normal daca obiectul este fara stare cea mai buna tehnica este de a folosi modul de activare SingleCall.

In modul de activare SingleCall, RT creaza un nou obiect pentru a servi fiecare cerere a clientului si va sterge obiectul cand cererea s-a completat. Acest mod este ideal pentru load balancing, cereri pentru mai multe servere (incarcarea judicioasa a fiecarui server cu cereri de la clienti).

Pentru a vedea diferentele dintre Singleton si SingleCall putem face urmatoarele modificari in cod:

// Suntem in client do

{

Console.WriteLine("5 + 2 = {0}", math.Add(5,2));

Console.Write("Enter q to quit: ");

}while (Console.ReadLine() != "q");

In proiectul MathServer, inregistram tipul sa se activeze in modul SingleCall prin schimbarea metodei RegisterWellKnownServiceType ca mai jos:

// Inregistram un tip ca fiind well-known

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(MathLibrary.Calculator), // The type to register "CalculatorURI.soap", // The well-known name WellKnownObjectMode.SingleCall // SingleCall or Singleton );

Probleme importante in .NET Remoting

#1 Trebuiesc create canale, inregistrate obiecte si alte configurari. Daca aceste detalii se schimba, codul trebuie recompilat.

#2 Pentru obiecte WKO, serverul trebuie sa creeze obiectele folosind ctor implicit.

#3 Clientul trebuie sa referentieze assembly ce contine tipul WKO. Deci trebuie distribuit assembly pe toate masinile client.

(28)

In continuare vom vedea cum pot fi depasite aceste probleme.

#1. Configurare (Remoting Configuration)

Problema poate fi rezolvata folosind un fisier de configurare. Acest fisier de configurare contine XML ce descrie parametri remoting pentru aplicatie. Este posibil sa avem doua fisiere de configurare, unul pentru server si altul pentru client, dar in acelasi timp putem crea un singur fisier de configurare atat pentru server cat si pentru client.

Toate setarile pentru remoting se gasesc sub elementul <system.runtime.remoting>. Acesta este un descendent al elementului <configuration>.

Trebuie sa completam ceva de genul urmator:

<configuration>

<runtime>

<!-- Put version binding redirects here -->

</runtime>

<system.runtime.remoting>

<!-- Put remoting configuration settings here -->

</system.runtime.remoting>

</configuration>

Configurare Server

In acest moment ne indreptam atentia asupra sectiunii remoting din fisierul de configurare.

Trebuie sa specificam tipul canalului si portul unde serverul va asculta pentru cereri de la clienti, tipul obiectului pe care dorim sa-l expunem, URL folosit ca nume WKO si modul de activare. In exemplul urmator putem vedea un fisier de configurare.

<configuration>

<system.runtime.remoting>

<application>

<service>

<wellknown mode="Singleton"

type="MathLibrary.Calculator, MathLibrary"

objectUri="CalculatorURI.soap" />

</service>

<channels>

<!-- NOTE: The following type attribute must actually be on a single line! It is broken up into multiple lines here for readability. -->

<channel port="8080"

type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting,

Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

</channels>

</application>

</system.runtime.remoting>

</configuration>

Elementul <application> incapsuleaza setarile remoting pentru aplicatie.

(29)

Elementul <service> descrie informatia despre tipul pe care aceasta aplicatie il expune. In cadrul acestui element putem specifica oricate elemente <wellknown>.

Atributul type specifica tipul expus. Acesta este compus din doua parti: numele calificat al tipului si numele assembly-lului.

Atributul objectUri specifica numele well-known ce este atribuit obiectului.

Elementul <channel> permite sa specificam tipul canalului si numarul portului pe care aplicatia ar trebui sa asculte pentru cereri.

Tipul canalului trebuie calificat complet

(System.Runtime.Remoting.Channels.Http.HttpChannel), de asemenea trebuie furnizat si asembly ce-l contine. Din cauza ca assembly este cu “nume tare” (strong name = complet descris), trebuie sa specificam numele tare al assembly, versiunea, cheia publica.

Presupunand ca am creat fisierul de configurare pentru server, atunci codul din SeverMain poate fi scris astfel:

using System;

using System.Runtime.Remoting; // ...

namespace MathServer {

class ServerMain {

static void Main(string[] args) {

// Citire informatii de configurare din // fisierul de configurare

RemotingConfiguration.Configure("MathServer.exe.config");

// Mentinere server in viata...

Console.WriteLine("Server started. Press Enter to end ...");

Console.ReadLine();

} } }

Avantajul major al unui asemenea fisier de configurare este ca il putem modifica fara a mai recompila aplicatia.

Configurare Client

Folosirea fisierului de configurare ne permite sa activam obiectele remote folosind new.

Nu mai trebuie sa recompilam clientul.

Pentru exemplul nostru, fisierul de configurare este:

<configuration>

<system.runtime.remoting>

<application>

(30)

<client displayName="MathClient">

<wellknown type="MathLibrary.Calculator, MathLibrary"

url="http://localhost:8080/CalculatorURI.soap" />

</client>

<channels>

<!-- NOTE: The following type attribute must actually be on a single line! It is broken up into multiple lines here for readability. -->

<channel type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting, Version=1.0.3300.0,

Culture=neutral, PublicKeyToken=b77a5c561934e089" />

</channels>

</application>

</system.runtime.remoting>

</configuration>

Codul pentru client devine:

using System;

using System.Runtime.Remoting;

using MathLibrary;

namespace MathClient {

class ClientMain {

static void Main(string[] args) {

// Incarca fisierul de configurare

RemotingConfiguration.Configure("MathClient.exe.config");

//Obtin proxy la obiectul remote Calculator math = new Calculator();

// Folosire obiect remote

Console.WriteLine("5 + 2 = {0}", math.Add(5,2));

Console.Write("Press enter to end");

Console.ReadLine();

} } }

Configurarea canalului

Configurarea canalului presupune numele, versiunea, cultura si cheia publica.

Putem crea channel templates ce incapsuleaza toate aceste informatii si in plus mai are si un ID.

Referirea la un asemenea channel template se face prin ID.

Template-ul pentru channel va trebui sa-l specificam sub <system.runtime.remoting> si nu sub <application>.

<configuration>

<system.runtime.remoting>

<application>

<channels>

<!-- Define channels used by the application here -->

Referințe

DOCUMENTE SIMILARE

Un cookie poate fi considerat ca fiind o variabilă valoarea ei este vehiculată via HTTP. între server Web (aplicația back-end) și

cerere – efectuată de un client – pentru accesul la reprezentarea unei resurse..

De¸si deja am ob¸tinut faptul c˘a A ^ = X este un estimator MVU (deoarece este eficient), utiliz˘am acum Teorema RBLS, care poate fi folosit˘a chiar ¸si atunci când nu exist˘a

– defineste tipul unui item cand este folosit in acelasi element ca si itemscope. – valoarea este un URL care

CGSociety pune la dispozitie un meniu complex si o multime de facilitati pentru utilizatori si membrii pentru a fi la curent cu ultimele noutati din domeniul.. CG,pentru a

Daca destinatia este intr-o retea conectata direct cu G, atunci G foloseste o intrare care arata costul folosirii retelei, si faptul ca nu este folosita nici o gateway (poarta)

Când este creat un nou element sau când este deschis un document, acest template este folosit pentru a crea cele trei elemente în următoarea ordine: documentul, fereastra cadru

Apa și izvoarele termale Sarein în Iran, Anahita Mirzaei; Karim Esmaeili; Niyousha Mirzaei (coord. Diana Boc-Sînmărghițan, Universitatea de Medicină și Farmacie