Transmettre une classe par le réseau

Bon, j’ai un petit (gros) problème.

J’ai une application en CSharp, qui gère des listes de classes (nous les appellerons classe A, classe B, classe C). J’ai un serveur qui contient plein de ces classes (disons 3 instances de A, 2 de B et une de C).

Un client se connecte, et il dit:

  • bonjour! donne moi la classe qui a la propriété “couleur” à “rouge”.

(ca je sais faire, toutes mes classes sont dérivées d’une classe abstraite qui demande l’implémentation d’une fonction “Search” qui possède 2 paramètres, à savoir la propriété et sa valeur).

Le serveur cherche et trouve la classe B (la première). Il veut donc la renvoyer au client.

Les questions sont:

  • 1 comment je renvoie la classe (serialize?)
  • 2 comment le client devine de quelle classe il s’agit?

Je sais qu’il existe des trucs pour sérializer les classes en CSharp (avec une interface) mais je ne sais pas vraiment comment les utiliser. Quelqu’un aurait un exemple?

[quote name=’[PERE]Cil’ date=’ 7 Feb 2005, 15:53’]Bon, j’ai un petit (gros) problème.

J’ai une application en CSharp, qui gère des listes de classes (nous les appellerons classe A, classe B, classe C). J’ai un serveur qui contient plein de ces classes (disons 3 instances de A, 2 de B et une de C).

Un client se connecte, et il dit:

  • bonjour! donne moi la classe qui a la propriété “couleur” à “rouge”.

(ca je sais faire, toutes mes classes sont dérivées d’une classe abstraite qui demande l’implémentation d’une fonction “Search” qui possède 2 paramètres, à savoir la propriété et sa valeur).

Le serveur cherche et trouve la classe B (la première). Il veut donc la renvoyer au client.

Les questions sont:

  • 1 comment je renvoie la classe (serialize?)
  • 2 comment le client devine de quelle classe il s’agit?

Je sais qu’il existe des trucs pour sérializer les classes en CSharp (avec une interface) mais je ne sais pas vraiment comment les utiliser. Quelqu’un aurait un exemple?
[right][post=“330024”]<{POST_SNAPBACK}>[/post][/right][/quote]

Pour le transfert des classes, si elles ne contiennent que des données (pas de méthodes dépendant de composants du serveur), il faut effectivement utiliser la sérialisation.
Si toutes les données de ta classe sont accessibles en lecture/ecriture par des accesseurs publics, tu peux utiliser le Serializer générique. Sinon il faut que tu implémentes l’interface ISerializable pour personnaliser la façon dont ta classe se sérialize et se désérialize.
Bien sur il faut que ton client comme ton serveur possède l’assembly qui contient ta classe.

Si ta classe contient des méthodes qui font appel aux composants disponibles uniquement sur le serveur, il te faut utiliser le .Net remoting.

Pour les détails : Gogo MSDN

Oui non enfin c’est pas ca la distinction remoting/serialization.

Si tu veux passer un clone de ta classe au client, tu serialize et le client deserialize. Il aura une instance differente mais a priori identique (depend de comment tu implemente ta serialization/deserialization).

Si tu veux que le client travaille sur la meme instance que celle qui est sur le serveur, tu utilise remoting. Dans ce cas la on s’approche d’une sorte de RPC objet en fait :stuck_out_tongue:

Ah je connais pas du tout le remoting… ca fonctionne comment? (je vais aller jeter un oeil du coté de la MSDN tiens…)

Mais a priori, toute modification de l’objet sur le serveur devrait se faire sur le client. Donc si le remoting permet de se passer de la fastidieuse retransmission de données (j’ai un doute que ca soit aussi simple que ca que tout soit automatique…) ca m’oterait une sacrée charge.

Mes classes ont malheureusement des méthodes, mais le client connait les classes “possibles” mais j’aimerais un code générique (parce que c’est du middle ware et que ce n’est pas moi qui gèrerait les classes a transmettre, mais un client qui implémentera les classes dérivées, et que je ne peux pas savoir a l’avance quelle classe ce sera).

[edit]

en fait, a la base je pensais transmettre le type de la classe avec la sérialisation, genre classe A, avec une fonction equivalente a getclass en php, et faire un truc du genre:

instance = new variable_qui_contient_le_nom_de_la_classe();

car effectivement, je n’ai pas besoin de l’instance même un clone peut être suffisant.

Pour connaitre le type orginal d’un objet tu utilises “myObj.GetType()” et tu le compare par exemple à “typeof(MyType)”.
Glop : je savais ca, mais je n’ai pas de super dons didactiques :s. Si tu as fait du Java, Remoting = RMI

Le problème, c’est que vu que je ne connais pas par avance le type de ma classe je peux pas faire dans le code un switch en fonction du type de la classe (vu que c’est le client qui va implémenter les classes).

Il faut savoir que si tu veux utiliser un objet (mais si tu ne l’utilises que via une classe abstraite qu’il spécialise) il te faut référencer l’assembly qui contient son type.
Si j’ai bien compris, tu as un certain nombre de classes abstraites que tu veux pouvoir spécialiser. Si ton client ET ton serveur ont accès aux assemblies qui définissent les types spécialisés, tu peux utiliser la sérialiser et tester si le type de ton objet hérite de telle ou telle classe abstraite : Tu peux faire ca avec “myObj.GetType().InHerits(typeof(MyAbstractClass))” (j’ai tappé ca de mémoire donc y’a p-e des erreurs d’orthographe/accents).

Bon je vais faire un schéma :stuck_out_tongue:

Alors!

[code]CLIENT

  • Classe UDPClient : se charge de récupérer les classes du serveur
  • Classe abstraite GenericObject : la classe de base
    ± abstract bool Search(property, value) : permet de chercher si un objet X a la propriété property à la valeur value.
    ± abstract bool Tick() : éxecuté une fois par cycle
    ± Classe ClasseA: n’est pas programmée par bibi, mais par quelqu’un d’autre. Contient des méthodes dérivées Search() et Tick()
    ± Classe ClasseB: n’est pas programmée par bibi, mais par quelqu’un d’autre
    ± Classe ClasseC: n’est pas programmée par bibi, mais par quelqu’un d’autre
  • ArrayList GenericObjectList: contient la liste des objets génériques du client (donc de type GenericObject)

SERVEUR

  • Classe UDPServer : se charge de récupérer les classes du serveur
  • Classe abstraite GenericObject : la classe de base
    ± abstract bool Search(property, value) : permet de chercher si un objet X a la propriété property à la valeur value.
    ± abstract bool Tick() : éxecuté une fois par cycle
    ± Classe ClasseA: n’est pas programmée par bibi, mais par quelqu’un d’autre. Contient des méthodes dérivées Search() et Tick()
    ± Classe ClasseB: n’est pas programmée par bibi, mais par quelqu’un d’autre
    ± Classe ClasseC: n’est pas programmée par bibi, mais par quelqu’un d’autre
  • ArrayList GenericObjectList: contient la liste totale des objets génériques (donc de type GenericObject)[/code]

Donc:

Le client cherche un objet dont la propriété couleur est a rouge. Le serveur va passer dans GenericObjectList à la recherche d’un objet qui répond true a l’appel de fonction Search(« color »,« red »). Jusque la pas de problème, toutes les classes sont dérivés de la classe mère et implémentées.

La le serveur trouve un objet qui correspond. Il doit normalement serializer la classe correspondante (ici, disons, ClasseB) et l’envoyer par le réseau au client, qui la, doit le désérializer.

  1. Comment je sérialize mon objet? la doc MSDN est pas du tout claire a ce sujet. Ils font un exemple tout fou avec un Singleton.
  2. Comment je m’assure, à la désérialisation que c’est un objet du meme type? Il faut que je le désérialize dans un objet de type « Object », ou « GenericObject »?
  3. Personne n’a de tuto super basique sur la serialisation? J’en ai pas vraiment trouvé de simple sur le net (avec des classes compliquées sur dotnet247, avec un singleton sur MSDN…)

Ou alors la sérialisation ne marche pas du tout dans mon cas et je dois utiliser autre chose?

Hop je crois que j’ai trouvé :P.

  1. Je serialize, en passant le type de la classe avec le résultat de GetType en entete de mon paquet réseau
  2. chez le client je lui claques un Activator.CreateInstance(String, String) en passant les paramètres (null, “nomdemaclasse”);

C’est bon?

[quote name=’[PERE]Cil’ date=’ 8 Feb 2005, 18:25’]Hop je crois que j’ai trouvé :P.

  1. Je serialize, en passant le type de la classe avec le résultat de GetType en entete de mon paquet réseau
  2. chez le client je lui claques un Activator.CreateInstance(String, String) en passant les paramètres (null, “nomdemaclasse”);

C’est bon?
[right][post=“330470”]<{POST_SNAPBACK}>[/post][/right][/quote]
Dans ce cas là, tu ne récupère pas les données que tu as sérializées

Déjà il faut que tes types implémentent IXmlSerializable.
Tu crées une classe message implémentant IXmlSerializable avec un champ publique de type Type et un champ public de type GenericObject.

pour serializer ta classe message en format xml, pas de probleme, tu utilise un élément “type” qui contiendra le nom du type (“TypeField.ToString()”) et un element “object” qui contiendra le résultat de la sérialisation XML de ton GenericObject

(

XmlSerializer serializer = new XmlSerializer(TypeField); serializer.Serialize(xmlWriter, ObjectField);
)

Pour la désérialisation, tu commence par désérialiser le champ type (Type.GetType(typeString)). Puis tu construit ton objet serializer avec ce type. et tu appelles la méthode Deserialize (et tu cast en GenericObject).

J’espère que mes explications te parraissent claire… si tu veux de plus amples explications, mp moi ton msn.

Oui j’avais oublié de préciser que dans mon objet créer par createinstance, je lui désérialize le contenu de mon paquet. Quoiqu’il en soit je vais te mp mon MSN :P.