IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

[Arch#] Architecture, IoC, AOP, Linq et co


Sujet :

Framework .NET

  1. #1
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut [Arch#] Architecture, IoC, AOP, Linq et co
    Bonjour !

    Je lance un projet personnel de Framework applicatif, son nom : Arch#

    Il s'agit, pour faire court, d'un Framework aidant la création d'application multicouche.

    Ca pourrait intéresser ceux qui aime la mise en place d'architecture orienté DDD, EF, l'IoC, la POA ou tout simplement des débutants en architecture.

    Un exemple d'objet business utilisant des fonctionnalités du framework :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    [Order("Title")]
    [Includes("Category")]
    public class Todo : Entity<int>
    {
        [Required]
        [StringLength(50)]
        public virtual string Title { get; set; }
     
        [Required]
        [StringLength(1000)]
        public virtual string Description { get; set; }
     
        [Increment]
        public int Version { get; set; }
     
        [AutoNowCreate]
        public virtual DateTime CreationDate { get; set; }
     
        [AutoNow]
        public virtual DateTime UpdateDate { get; set; }
     
        public virtual Category Category { get; set; }
    }
    Je vous laisse deviner a quoi servent les Tags

    En théorie ces technologies sont indépendantes d'EF et des provider NHibernate et mongoDB vont venir.

    Si vous avez envie d'en savoir plus, le projet est ici : http://arch.codeplex.com/ une release avec code source et un petit exemple de développement avec MVC 2 est disponible.

    Attention : C#4 et VS 2010 requis

    Si vous avez des commentaires ou des idées je suis preneur

    A+

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Moi j'aime bien, du code clean, simple et utile.
    Si tu veux un coup de main ?

  3. #3
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Bonjour BAf!

    Merci pour ton retour sympathique, je suis content que ça plaise

    Vis à vis d'un coup de main pourquoi pas, il faut voir sous quel forme ?

    Déjà quelques conseils de personnes ayant fait pas mal de boulot d'architecture m'intéresse beaucoup !

    Par exemple pour le moment je réfléchis à comment refaire le mécanisme d'interception, je trouve que l'api n'est pas assez bien fait.

    Au début c'était plus clean mais il y avait une dépendance forte entre les objets business de l'application utilisant le framework et la DLL Arch.
    Ça me gène de partager toute la dll Arch - par exemple - dans un contexte d'application client/serveur partageant le même model objet.
    Le problème c'est un peu ça : les objets business ont besoin de connaitre les aspects (Order, Includes, AutoNow, ...) mais ces derniers font pas mal de business et c'est difficile de les découpler d'Arch.
    Pour le moment les aspects "Order" et "Includes" se contentent de copier les paramètres (via reflection) dans le repository qui gèrent lui même le comportement résultant de ces aspects.
    Donc si tu as des idées d'amélioration en gardant un découplage fort ...

    Après je compte créer de nouveaux intercepteurs, notamment pour la validation (avant create et update) utilisant les DataAnnotations et peut être aussi les ValidationAspect
    Si quelqu'un as des idées d'autre types d'interception qui pourraient être intéressant je suis prêt à me pencher dessus

    Sinon j'ai mis le projet en Alpha pas d'un point de vue où il n'est pas exploitable (j'ai déjà utilisé des mécanismes proches dans des projets réels) mais dans le sens où je compte y ajouter quelques blocs et que l'API risque de bouger encore un peu. Se mettre en mode 1.0 fait perdre de la flexibilité dans les possibilités de modifier le projet et je préfère attendre d'avoir eu quelques retours.

  4. #4
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    Tu fais un usage intensif de la reflection, non ?

    Pour ce qui est de ton mécanisme d'interception, j'ai un projet perso en ce moment qui pourrait te donner quelques pistes intéressantes, et par là même te permettre de te débarrasser de la dépendance à la classe Entity<T>.

    Par contre, j'hésite un peu entre diverses architectures pour gérer les types génériques, dans mon projet.

  5. #5
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    En effet il y a un peu trop de reflexion à mon gout.

    Par exemple le autonow execute cela à chaque update :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void Intercept<T>(T entity, MemberInfo member)
    {
        (member as PropertyInfo).GetSetMethod().Invoke(entity, new object[] { DateTime.Now });
    }
    On pourrait mettre en cache le GetSetMethod ... Sinon (juste) le invoke à partir d'une méthode récupéré via réflexion est plus long qu'un appel standard ?

    Ma classe entity n'est pas obligatoire dans mon framework, elle donne juste un "coup de main" sur les GetHashCode, Equals et une propriété "IsTransient".

    J'ai réglé mon problème de WCF avec les entity<T> mais si tu as quelque chose d'intéressant pour s'en "débarrasser" je suis pas contre

  6. #6
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    L'invoke tout court sera plus lent qu'un appel direct, sans reflexion, oui.

    Tu peux t'en passer de diverses manières, en fait.
    Avec une lambda expression, une méthode dynamique, un proxy dynamique ou carrément en injectant du code dans la méthode interceptée.

    Le proxy va t'obliger à te passer d'une instanciation simple avec l'opérateur new.
    L'injection de code, ça dépend comment tu t'y prend.

  7. #7
    Membre émérite Avatar de meziantou
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Points : 2 439
    Points
    2 439
    Par défaut
    ou carrément en injectant du code dans la méthode interceptée.
    Comme le fait PostSharp.
    http://www.sharpcrafters.com/

  8. #8
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Ces objets sont créés par unity qui, il me semble, peut faire de l'interception par proxy dynamique.
    Injecter le code me semble compliqué, certain intercepteurs s'appliquent à toutes les entités d'autres à certaines entités, d'autre uniquement au repository, d'autres à certaines entités sur certains "évènements" et d'autres encore sur certaines entités, à certains "évènements" sur certaines propriétés, ... Casse tête
    Au final le plus simple serait de créer une expression lambda à partir d'un expression tree créé une fois, compilé et mis en cache.

    Par contre je vois pas bien ce que tu veux dire par méthode dynamique ?

    Il va falloir que je réfléchisse à ces approches mais je me demande si je vais réussir à garder une API flexible permettant de créer ses propres intercepteurs business facilement. En tout cas merci pour tes pistes

  9. #9
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Citation Envoyé par meziantou Voir le message
    Comme le fait PostSharp.
    http://www.sharpcrafters.com/
    Je ne veux pas de dépendance à PostSharp

  10. #10
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    Postsharp est très sympa, mais il a en effet l'énorme problème de créer des dépendances après la compilation, alors qu'en toute logique un framework AOP devrait éviter ce genre de chose.
    On en avait déjà parlé à deux, anthyme, je crois, non ?

    Pour les méthodes dynamiques, il s'agit de la classe DynamicMethod.
    Globalement, c'est ce qu'on utilisait avant Linq et les lambda-expressions pour assembler du code remplaçant la reflexion.
    On l'utilise toujours dans les cas que Linq ne peut gérer. Ca demande quelques notions en MSIL, ceci dit, c'est loin d'être vraiment compliqué.

    Sinon, je me demande si on ne devrait pas, d'une certaine manière, bosser ensemble sur ce point du projet (l'interception, je veux dire).
    J'ai remarqué que tu t'intéressais pas mal à l'injection dynamique de code, à l'AOP, tout ça...

    De mon côté, le projet perso que j'ai mentionné plus haut est une librairie de manipulation de code MSIL, genre Mono.Cecil, mais utilisable au runtime.
    Et l'idée était, notamment, de pouvoir créer des intercepteurs, comme les tiens, notamment.

  11. #11
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Citation Envoyé par anthyme Voir le message
    Ces objets sont créés par unity qui, il me semble, peut faire de l'interception par proxy dynamique.
    Injecter le code me semble compliqué, certain intercepteurs s'appliquent à toutes les entités d'autres à certaines entités, d'autre uniquement au repository, d'autres à certaines entités sur certains "évènements" et d'autres encore sur certaines entités, à certains "évènements" sur certaines propriétés, ... Casse tête
    Au final le plus simple serait de créer une expression lambda à partir d'un expression tree créé une fois, compilé et mis en cache.

    Par contre je vois pas bien ce que tu veux dire par méthode dynamique ?

    Il va falloir que je réfléchisse à ces approches mais je me demande si je vais réussir à garder une API flexible permettant de créer ses propres intercepteurs business facilement. En tout cas merci pour tes pistes
    Le truc c'est que ça reste du marshaling et du remoting, donc sur les perf tu vas le sentir.
    En utilisant le code émit, tu devrais être mieux. Mais

    Pour la gestion de l'interception, regardes les pointcuts de Spring, c'est pensé pour ça.

  12. #12
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Oui on avait déjà parlé de postsharp, personnellement j'adore ce projet et je l'ai pas mal utilisé dans mes applications. Mais je ne veux pas l'utiliser car :
    - Le projet impose un dépendance au compilateur postsharp qui nécessite une installation (ou une bidouille dans les configuration msbuild avec le binaire de postsharp à balader)
    - L'(unique!) auteur de postsharp n'est pas très fiable : il est seul, par moment il a parlé de tout arrêter et finalement postsharp 2.0 est (en partie) payant
    - J'aimerais limiter au maximum les dépendances dans mon framework, il y a déjà unity qui pourrait bloquer les fans de spring.net, ninject ou autre

    Je veux bien qu'on partage un peu nos approches, pour le moment je vais jeter un oeil aux mécanismes d'injection d'unity et de spring et je ferrait un retour.

    D'ailleurs je devais regarder pour le coté client des proxy dans un poc que je fais avec :
    - EF4 via des poco proxy et lazy loadable
    - WCF en couche de service
    - Silverlight 4

    J'essai d'avoir le même modèle objet transverse sur l'ensemble des couches (oui je sais on lit partout que les poco proxy d'EF sont pas terrible pour se balader dans WCF et qu'il vaut mieux prendre des tracking entity ou RIA/Data Services mais bon j'ai une vision différente du dev ... )
    Le but est de conserver le même modèle objet proxifié pour EF dans la couche Data, deproxifié sur la couche service, et proxifié avec une orientation INotifyPropertyChanged dans la couche UI
    Pour le moment tout marche et passent bien à travers WCF, il me manque juste la proxification coté UI

    Sinon pour le code emit direct à la mano, je ne pense pas ... S'il faut coder de l'Emit à chaque fois qu'on veut créer un aspect ça limite l'extensibilité de la chose.

  13. #13
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    En fait, tu n'as pas forcément besoin d'émettre du code msil pour "proxifier/déproxifier".
    Tu peux lire le code de plusieurs méthodes et les assembler en une seule avec diverses règles.
    C'est d'ailleurs l'une des l'idée de base de mon projet.

    En gros, tu devrais être capable à partir d'un *vrai* POCO tout bête, de générer, lors de l'exécution, autant de types basés à la fois sur ce POCO et sur un jeu de règles que tu définis toi-même.
    En fait, le POCO peut même être une simple interface, ça marche aussi.

    C'est plus vraiment des proxies, à ce niveau là, dans la mesure où tu n'as pas vraiment d'objet interne "proxifié".

  14. #14
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Qu'est ce que ton projet apporte par rapport à ce qui existe ? Comme unity ?

  15. #15
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    Qu'est-ce que t'apporterait la possibilité de :
    - modifier un assembly avant son exécution, au runtime ?
    - générer plusieurs versions du même type, ayant des comportements différents suivant tes besoins ?
    - postsharp, sans dépendance à une dll, une fois le code manipulé

    Ce genre de truc.

    Un exemple concret...
    J'ai une appli dans lequel j'ai besoin de gérer la sécurité et d'injecter du code avant/après l'exécution de certaines méthodes. Ceci dans le cadre d'un système de services pluggués à un hôte.

    Le service se résume à quelque chose de ce style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public interface MonService
    {
      [Restricted(RestrictionLevel.AdminOnly)]
      void Foo();
     
      [Restricted(RestrictionLevel.CustomAndAdmin)]
      void Foo(string bar);
    }
    La dll contenant MonService n'a aucune connaissance, nulle part, du système de gestion de droits. L'attribut Restricted n'est que pure donnée. Aucun comportement : ça ne fait que décrire qui a le droit de lancer cette commande.

    A côté de ça, l'hôte gère le reste avec la possibilité de "brancher" d'autres services avant/après les appels aux méthodes des différents services.

    Le truc, ici, c'est que tout ce système est interchangeable au runtime.

    Par contre, pour le moment, c'est clairement en alpha. Comme je te racontais, j'ai quelques hésitations sur la manière de gérer les objets génériques, donc... Pas mal de refactoring en vue.

  16. #16
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    C'est intéressant ! C'est publié quelque part ?

  17. #17
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    Tant que les interfaces du projet sont instables, je préfère ne pas le publier... Ca servirait pas à grand chose à part dire "on peut faire ça". :p

    Là, je t'en parlais surtout parce qu'une des possibilités de ce projet pourrait être utile dans le tien. Et pour cette utiliser cette fonctionnalité, tu n'as pas besoin du projet entier, tu peux la reproduire assez facilement et rapidement.

    L'idée serait de générer non pas un type complet, mais un proxy via reflection.emit

    Les méthodes que tu souhaites intercepter seraient "décorées" par un délégué qui aurait une signature identique à Invoke.
    Le fonctionnement serait exactement le même, excepté que l'appel à cette méthode serait direct : ça te permet de te passer de la reflexion (en dehors de la création du type proxy, mais ça, tu le fais qu'une seule fois).

    En clair, tu remplaces GetGet/SetMethod et MethodInfo.Invoke par un opcode call.

  18. #18
    Membre éprouvé Avatar de anthyme
    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    1 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Points : 1 257
    Points
    1 257
    Par défaut
    Je vais attendre avec impatience ce framework alors

    Pour ma part je commence à
    1 - faire quelque chose qui marche
    2 - faire une bonne API
    3 - faire quelque chose de performant

    Pour le moment j'approche tout juste de la fin de la 1 en ayant pris en minimum en compte le 2 et 3

    Pour mon POC ntier j'ai regardé du coté de unity interception / linfu et castle.dynamicproxy pour mes proxy coté silverlight 4

    - Unity correspond pas vraiment à mes besoin
    - Linfu étrangement me fait des erreur du type "le runtime est mis dans un état instable" peut etre que c'est du au fait que la dll ciblait sl3 ...
    - Castle marche super bien pour sa part, je n'ai plus qu'a intégrer la proxification/deproxification dans un behavior WCF, je vois pas vraiment comment procéder ... Va falloir que je cherche un peu

  19. #19
    Membre expérimenté Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Points : 1 539
    Points
    1 539
    Par défaut
    Il y a quelques temps j'avais réalisé un ORM capable de transiter à travers un service WCF tout en préservant ses capacités de persistance de façon transparente.

    En gros, ça permettait de persister tout en les distribuant à tous les clients connectés au service, par exemple.
    Simplement en faisant ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    classe.propritete = valeur;
    Ou encore en déférant la persistance/distribution, lors d'un appel explicite à une méthode de "sauvegarde".

    Je sais pas si ça pourrait te donner des idées, si jamais je retrouve le code.

  20. #20
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par anthyme Voir le message
    En effet il y a un peu trop de reflexion à mon gout.

    Par exemple le autonow execute cela à chaque update :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void Intercept<T>(T entity, MemberInfo member)
    {
        (member as PropertyInfo).GetSetMethod().Invoke(entity, new object[] { DateTime.Now });
    }
    On pourrait mettre en cache le GetSetMethod ... Sinon (juste) le invoke à partir d'une méthode récupéré via réflexion est plus long qu'un appel standard ?
    Oui sensiblement. Le mieux dans ce cas est de procéder par injection de code : on utilise la Reflection la première fois, pour déterminer le code à injecter puis on injecte le code (avec "Emit") et ensuite on a des perf normales.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

Discussions similaires

  1. cherche tuto spring sans blabla sur ioc aop
    Par pschiit dans le forum Spring
    Réponses: 0
    Dernier message: 18/05/2011, 14h29
  2. Architecture XML / requete LINQ
    Par bidault dans le forum Linq
    Réponses: 1
    Dernier message: 06/03/2011, 15h53
  3. [AOP et IOC] Solution en .net
    Par anthyme dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 17/07/2007, 15h04
  4. [Architecture] Questions DB, Arch, Tech pour un project
    Par Ultiny dans le forum Développement Web en Java
    Réponses: 3
    Dernier message: 02/05/2006, 15h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo