DMI's Blog sur les technos .NET(dotnet) et J2EE

.NET Remoting (Visualiser avec IE -Internet Explorer-)

Dans cet article je vais expliquer en quelques étapes comment faire une application distribué avec la technologie

 

Dans cet article je vais expliquer en quelques étapes comment faire une application distribué avec la technologie .NET Remoting.

 

L’environnement technique :

 

IDE : Visual studio 2003 avec le .NET Framework 1.1

Langage : C#

 

Présentation

 

.NET Remoting est une technologie offerte avec le Framework .NET et permet de faire de la programmation distribuée. La programmation distribuée permet par principe d’exécuter un processus sur plusieurs machines. Le but étant d’exécuter des parties du processus sur des machines qui sont le plus disposées à l’effectuer (gros calculs, traitement métier, …).

 

Scenarii

 

Voici notre scenario :

 

Nous disposons d’une application de gestion de compte bancaire qui est composée de trois applications reparties dans toute la France.

 

  • La première application a pour but de récupérer dans une DB le montant du découvert d’un client identifié

 

  • La seconde, permettra à partir du montant de découvert d’effectuer des calculs permettant de savoir le montant des agios

 

  • La troisième, collectera les informations transmises par les deux premières applications et prendra la décision d’envoyer un courrier au client ou pas en étudiant le rapport découvert/agios.

 

 

Pour visualiser le schéma vous devez avoir un web browser IE


Mise au point

 

Il est utile de comprendre l’architecture du .NET remoting.

En gros : vous avez d’un côté un serveur puis de l’autre un ou plusieurs client comme ci-dessous.

 

Pour visualiser le schéma vous devez avoir un web browser IE

 

L’échange de données peut se faire via HTTP ou TCP (dans notre cas nous utiliserons le protocole TCP). HTTP est plus adapté pour des communications distantes nécessitants le réseau web et TCP pour des communications en réseaux locaux (format binaire, plus performant). Le format d’échange peut être du Xml ou du binaire.

 

 

Important : Dans notre cas les applications 1 et 2 sont des serveurs et l’application 3 le client

 

Mise en pratique

 

 

  • Créez une solution nommée _NETRemoting sous visual studio .NET,
  • Ajoutez une application console (projet) nommée Svr_App1 à la solution,
  • Ajoutez un projet ClassLibrary nommé Lib_App1 à la solution,
  • Ajoutez une application console (projet) nommée Svr_App2 à la solution,
  • Ajoutez un projet ClassLibrary nommé Lib_App2 à la solution,
  • Ajoutez une application WinForm (projet) nommée clt_App3 à la solution.

 

 

Il est intéressant de savoir que le client ne manipule jamais les objets hébergé par le serveur mais passe par se qu’on appelle des proxies.

En effet, les proxies sont les représentants locaux des objets distants. Pour communiquer avec un objet distant, on instancie un proxy qui sera la représentation locale de cet objet. On manipule le proxy comme si c’était notre objet distant.

 

Dans notre cas nous allons avoir deux proxies (un pour l’application 1 et l’autre pour l’application 2). Un proxy étant un objet, il est donc représentable par une classe ou une interface.

 

 

A ce stade nous avons toutes les entités nécessaires, reste plus qu’à les meubler.

 

Projet Lib_App2

 

Son rôle est de calculer un agio à partir d’un montant représentant le découvert bancaire

 

Renommer class1 en LibApp2 ainsi que le fichier (LibApp2.cs)

La classe LibApp2 doit forcément dériver de MarshalByRefObject

 

Ajouter au projet une méthode nommée float getAgio(float fDec)

 

Le projet Lib_App1

 

Son rôle est de récupérer le montant du découvert de la base de données puis d’interroger l’application 2 pour avoir le montant de l’agio.

 

Renommer class1 en LibApp1 ainsi que le fichier (LibApp1.cs)

La classe LibApp1 doit forcément dériver de MarshalByRefObject

Ajouter une méthode nommée void getAgioAndDec(long lIDClient, ref float fDec, ref float fAgio)

Ajouter une interface nommée IApp2 (proxy de Lib_App2) –fichier IApp2.cs-

 

 

Le projet Svr_App2

 

Renommer Class2 en App2 ainsi que le fichier (App2.cs au lieu de Class1.cs)

Ajouter une référence du projet Lib_App2

 

Le projet Svr_App1

 

Renommer Class1 en App1 ainsi que le fichier (App1.cs au lieu de Class1.cs)

Ajouter une référence du projet Lib_App1

 

Le projet clt_App3

 

Ajouter un bouton, une textbox, et un label

Dans le textbox vous saisirez l’ID du client et l’appui sur le bouton invoquera les méthodes distantes puis le résultat sera affiché dans le label.

Ajouter une interface nommée IApp1 (proxy de Lib_App1) –fichier IApp1.cs-

 

 

Au niveau des deux serveurs

 

Ajouter les références suivantes (fichier App1.cs et App2.cs) :

using System;

using System.Collections;

using System.Runtime.Remoting;

using MyTcpChannel = System.Runtime.Remoting.Channels.Tcp.TcpChannel;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels;

 

Attention: Vous devez ajouter la référence de l’assembly System.Runtime.Remoting à vos projets (Click droit sur le projet puis ajouter référence)

 

Pour “servir un objet” on doit:

 

  1. Ouvrir un canal selon un protocole et sur un port (1234 pour Svr_App1 et 5678 pour Svr_App2)

 

  1. Enregistrer le canal ouvert précédemment

 

  1. Publier son type avec l’URI et le mode pour y accéder

 

Et tout ça dans la méthode main

 

Au niveau du client (clt_App3)

 

using System;

using System.Collections;

using System.Runtime.Remoting;

using MyTcpChannel = System.Runtime.Remoting.Channels.Tcp.TcpChannel;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels;

 

Attention: Vous devez ajouter la référence de l’assembly System.Runtime.Remoting à vos projets (Click droit sur le projet puis ajouter référence)

 

 

 

Pour visualiser le schéma vous devez avoir un web browser IE

 

Codes Sources

 

Si vous voulez les codes complets envoyez moi un mail à l’@ suivante :bossiel@yahoo.fr

 

 

 

 

 

 

Svr_App1 :App1.cs

 

using System;

using System.Collections;

using System.Runtime.Remoting;

using MyTcpChannel = System.Runtime.Remoting.Channels.Tcp.TcpChannel;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels;

 

namespace Svr_App1

{

/// <summary>

/// Description résumée de Class1.

/// </summary>

class App1

{

/// <summary>

/// Point d'entrée principal de l'application.

/// </summary>

[STAThread]

static void Main(string[] args)

{

BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();

serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();

IDictionary props = new Hashtable();

props["port"] = 1234;//port

//(1): Ouvrir un canal selon le protocole tcp et sur un port 1234

// Enregistrer le canal ouvert précédemment

MyTcpChannel _tcpChannel = new MyTcpChannel(props,clientProv,serverProv);

ChannelServices.RegisterChannel(_tcpChannel);

 

//(2): Publier son type avec l’URI et le mode pour y accéder

RemotingConfiguration.RegisterWellKnownServiceType(typeof(Lib_App1.LibApp1),"Svr_App1",WellKnownObjectMode.SingleCall);

Console.Write("**********************************************\n");

Console.Write(" MON SERVEUR Svr_App1 \n");

Console.Write("***********************************************\n");

Console.Write("Moi je suis un serveur d'application conçu pour Lib_App1 distant\nqui sera utilisé par un client autonome (App3) via tcp/http au format binaire ou soap\n");

Console.Write("\n\n");

Console.Write("-Je viens de me lancer sur tcp:1234\n\n");

Console.Write("-Je viens de demarrer l'objet distant ok\n\n");

Console.Write("[Entree] pour quitter");

Console.ReadLine();

ChannelServices.UnregisterChannel(_tcpChannel);

}

}

}

 

 

 

Lib_App1 :LibApp1.cs

 

using System;

using System.Collections;

using System.Runtime.Remoting;

using MyTcpChannel = System.Runtime.Remoting.Channels.Tcp.TcpChannel;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels;

 

namespace Lib_App1

{

/// <summary>

/// Description résumée de Class1.

/// </summary>

public class LibApp1 :MarshalByRefObject

{

public LibApp1()

{ }

public void getAgioAndDec(long lIDClient, ref float fDec, ref float fAgio)

{

//les calcul sont fictifs: ajouter du code pour acceder à une DB

if(lIDClient > 0)

{

fDec = -152;//toujours

fAgio = getAgio2(fDec);

}

}

/// <summary>

/// Cette methode appel l'objet distant Lib_App2 pour avoir le montant de l'agio

/// sachant à combien s'éleve le découvert.

/// Pour que cette méthode marche il faut que le serveur Svr_App2 soit démarré

/// </summary>

/// <returns></returns>

private float getAgio2(float fDec)

{

//(1): Ouverture du canal selon le protocole Tcp

MyTcpChannel _tcpChannel = new MyTcpChannel(1);

//(2): Enregistrement du canal ouvert précédemment

ChannelServices.RegisterChannel(_tcpChannel);

// (3): Récupération d'une référence de l'objet distant Lib_App2 hebergé par Svr_App2

Lib_App2.LibApp2 pxy_App2 = (Lib_App2.LibApp2)RemotingServices.Connect(typeof(Lib_App2.LibApp2),

"tcp://localhost:5678/Svr_App2");

try

{

return pxy_App2.getAgio(fDec);

 

}

catch(Exception ex)

{

return -1;

}

finally

{

// (4): Fermeture et deréférencement du canal

ChannelServices.UnregisterChannel(_tcpChannel);

}

}

}

}

 

ctl_App3 :IApp1.cs

 

/*C'est le proxy de l'objet Lib_App1*/

using System;

 

namespace Lib_App1

{

public interface LibApp1

{

void getAgioAndDec(long lIDClient, ref float fDec, ref float fAgio);

int test();

}

}

 

clt_App3 : Form1.cs

 

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Runtime.Remoting;

using MyTcpChannel = System.Runtime.Remoting.Channels.Tcp.TcpChannel;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels;

 

 

namespace clt_App3

{

/// <summary>

/// Description résumée de Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

private System.Windows.Forms.TextBox textBox1;

private System.Windows.Forms.Button button1;

private System.Windows.Forms.Label label1;

/// <summary>

/// Variable nécessaire au concepteur.

/// </summary>

private System.ComponentModel.Container components = null;

 

public Form1()

{

//

// Requis pour la prise en charge du Concepteur Windows Forms

//

InitializeComponent();

 

//

// TODO : ajoutez le code du constructeur après l'appel à InitializeComponent

//

}

 

/// <summary>

/// Nettoyage des ressources utilisées.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

 

#region Code généré par le Concepteur Windows Form

/// <summary>

/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas

/// le contenu de cette méthode avec l'éditeur de code.

/// </summary>

private void InitializeComponent()

{

this.textBox1 = new System.Windows.Forms.TextBox();

this.button1 = new System.Windows.Forms.Button();

this.label1 = new System.Windows.Forms.Label();

this.SuspendLayout();

//

// textBox1

//

this.textBox1.Location = new System.Drawing.Point(16, 16);

this.textBox1.Name = "textBox1";

this.textBox1.TabIndex = 0;

this.textBox1.Text = "45286";