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

Windows Communication Foundation .NET Discussion :

Intercepter les objets dans un client WCF


Sujet :

Windows Communication Foundation .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 : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut Intercepter les objets dans un client WCF
    Bonjour,

    Il faudrait que je m'interface dans un client WCF (exécuté en silverlight) afin de :
    - Intercepter l'instanciation des objets provenant du serveur pour les transformer en proxy
    - Intercepter l'envoi des fichiers du client vers le serveur pour les deproxifier et les retransformer en "classe de datacontract standard"

    Pour faire cela j'imagine qu'il faut que je créer un behavior WCF mais pour tout dire je n'ai aucune idée de quel classe utilisé ni de où et comment l'injecter dans mon client.

    Si vous pouvez me donner quelques pistes ...

    merci

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Pas de pistes, pas même pour l'utilisation de behavior coté client ?

    J'avoue avoir du mal à glaner des infos sur le net ...

  3. #3
    Membre extrêmement actif
    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
    Par défaut
    Il faut que tu implément ton propre ContractBehavior ou operation behavior,
    où alors autre solution : ta propre sérialisation.

    En même temps je ne comprends pas trop ce que tu veux faire au final, donc si tu as plus d'infos, peut être que je n'ai pas compris.

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Mon but est d'avoir une architecture Client/Serveur : EF4 / WCF / Silverlight.

    Mais sans avoir à créer 3 modèles de classe (Entity, DTO, Presentation Model) "en code"

    Dans les faits j'écrirais un seul modèle de classe pour l'ensemble de l'application mais il y en aura bien 3 types différents :
    - Mon modèle de classe sera relativement simple (poco) et utilisé en tant que DTO
    - Ce modèle aura une création de type dynamique proxyfié coté serveur pour répondre aux besoins d'EF4 (proxification automatique par le framework EF4)
    - Ce modèle sera également proxyfié coté UI pour répondre au besoins UI (notamment INotifyPropertyChanged)

    J'aimerai que cette architecture soit au maximum transparente pour le développeur.

    Coté serveur, EF4 créé des Proxy seul et j'ai bien réussi à deproxifier les objets provenant de ma couche Business via un behavior WCF qui utilise le DataContractProxyResolver.

    Maintenant il me reste plus qu'a reproxifié (DTO => Presentation Model) les objets coté client pour les objets allant dans le sens Serveur => WCF => Client et les deproxifier (Presentation Model => DTO) coté client pour les objets allant dans le sens client => WCF => Serveur
    (Pour le moment je pense utiliser Caste.DynamicProxy , j'ai réussi a rendre mes objets INotifyPropertyChanged avec ce framework).

    Si je ne pense pas avoir de problème à le faire via une surcouche de mes clients je pense que ca serait plus clean d'intégrer ça sous forme de behavior WCF "transparents"

    Je vais regardé les OperationBehavior mais je me demande si je vais pouvoir remplacer les objets normaux par des proxyfier de cette façon.

  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 : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Ah oui et DataContractSerializer est sealed ... comment je pourrais modifier son comportement ?

  6. #6
    Membre extrêmement actif
    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
    Par défaut
    Alors tu peux intervenir sur

    IDispatchMessageInspector qui te permet d'intervenir sur les messages en entrée sortie

    et

    DataContractSerializerOperationBehavior qui va te permettre de manipuler le serializer (au moins le Xml dans celui là).

    Tu trouvera un bon tuto ici :WCF Behaviors

    En fait ce qui me semble le plus simple c'est que tu sérialises l'objet en proxy in fine si c'est possible.

    en gros si je comprend bien :
    - Tu veux créer un objet Lambda poco
    - Si il est exploité sur WCF tu veux le décorer avec un INotifyPropertyChanged ou autres méthodes propres à l'UI
    - Si il est exploité par EF tu veux le décorer avec l'entityobject ou autre ?


    DataContractSerializer est sealed, mais il dérive de XmlObjectSerializer et en est une implémentation qui est définie au niveau du OperationBehavior.

    Good luck, ça m'a l'air chaud lapin ton truc quand même !

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Je suis chaud lapin en ce moment

    En effet t'as bien compris le truc, je vais suivre tes pistes quand j'aurais un moment et je ferrai un retour !

    Merci @+

  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 : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    A priori tes classes ne sont pas accessible dans silverlight, après avoir creuser encore plus on dirait que la bonne interface pour intercepter les objets semble être IClientMessageFormater.

    Je récupère donc mes objets normaux provenant du service que je doit proxifier et les renvoyer.

    Il n y a plus qu'a recréer des objets proxifié et copier les données dans ces objets sur l'ensemble du graphe d'objet récupéré.
    A la main c'est un peu galère, je comptais utiliser AutoMapper ou EmitMapper pour mapper mes objets mais il y a un probleme ...

    Castle.DynamicProxy ne me donne pas un simple type que l'on pourrait utiliser normalement (Activator.CreateInstance), il faut que je passe par des méthodes de sa proxyFactory, ce que ne peux pas faire Auto/Emit Mapper ... Zut !

    Je vais regarder du coté d'autres frameworks de dynamic proxy si je ne pourrais pas avoir un type créé plutôt que devoir créer les objets.
    Il me semble que linfu ne marche pas bien dans silverlight 4, il me reste plus que spring ...

  9. #9
    Membre extrêmement actif
    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
    Par défaut
    Citation Envoyé par anthyme Voir le message
    A priori tes classes ne sont pas accessible dans silverlight, après avoir creuser encore plus on dirait que la bonne interface pour intercepter les objets semble être IClientMessageFormater.

    Je récupère donc mes objets normaux provenant du service que je doit proxifier et les renvoyer.

    Il n y a plus qu'a recréer des objets proxifié et copier les données dans ces objets sur l'ensemble du graphe d'objet récupéré.
    A la main c'est un peu galère, je comptais utiliser AutoMapper ou EmitMapper pour mapper mes objets mais il y a un probleme ...

    Castle.DynamicProxy ne me donne pas un simple type que l'on pourrait utiliser normalement (Activator.CreateInstance), il faut que je passe par des méthodes de sa proxyFactory, ce que ne peux pas faire Auto/Emit Mapper ... Zut !

    Je vais regarder du coté d'autres frameworks de dynamic proxy si je ne pourrais pas avoir un type créé plutôt que devoir créer les objets.
    Il me semble que linfu ne marche pas bien dans silverlight 4, il me reste plus que spring ...
    Unity ? A priori il fonctionne bien en SL ? Et puis Spring c'est du proxy en runtime, ça coute bonbon en perfs..Sur deux ou trois aspects soit, sur toute une archi, tu vas souffrir...

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Unity pose le même problème que Castle car il doit construire lui même les objets.
    A priori unity a une approche proxy Full AOP et je ne veux pas tagguer mes entité d'attributs spécifique à une couche.
    et Même si j'aime beaucoup unity, je veux bien l'utiliser pour construire mes couches mais pour mes objets business je préfère éviter ...

    Je me suis lancé sur une nouvelle approche ... créer mon type proxifié moi même ! Je tâtonne encore un peu je n'ai pas l'habitude de ce genre de manip mais je pense que j'avance dans la bonne direction malgres un petit bug qui me bloque encore un peu.

    Pour ceux que ça intéresse, je montre mon approche.

    Le but en gros est de generer ce type la au runtime :

    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
    24
    25
    26
    27
    28
    public class CategoryProxy : Category
    {
        public override string Name
        {
            get
            {
                return base.Name;
            }
            set
            {
                base.Name = value;
                RaisePropertyChanged("Name");
            }
        }
     
        public override IList<Todo> Todos
        {
            get
            {
                return base.Todos;
            } 
            set
            {
                base.Todos = value;
                RaisePropertyChanged("Todos");
            }
        }
    }
    A partir de ce type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [DataContract(IsReference = true)]
    public class Category : Entity<int>
    {
        public Category() : base()
        {
            Todos = new List<Todo>();
        }
     
        [DataMember]
        public virtual string Name { get; set; }
     
        [DataMember]
        public virtual IList<Todo> Todos { get; set; }
    }
    De façon générique évidement

    Pour le moment j'ai écris ce code :

    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    public static class Proxy
    {
        private static Dictionary<Type, Type> mappings = new Dictionary<Type, Type>();
     
        public static Type GetProxyType<T>()
        {
            var type = typeof(T);
            return (GetProxyType(type));
        }
     
        public static Type GetProxyType(Type type)
        {
            if (mappings.ContainsKey(type)) return mappings[type];
     
            AssemblyName name = new AssemblyName();
            name.Name = "ObjectProxies";
     
            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
     
            ModuleBuilder module = assembly.DefineDynamicModule("Proxies");
     
            TypeBuilder proxy = module.DefineType(type.Name + "Proxy", TypeAttributes.Public | TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, type);
     
            foreach (PropertyInfo propertyInfo in type.GetProperties().Where(p => p.CanWrite && p.CanRead))
            {
                PropertyBuilder property = proxy.DefineProperty(propertyInfo.Name, propertyInfo.Attributes, propertyInfo.PropertyType, null);
     
                property.SetGetMethod(BuildGetProperty(proxy, type, propertyInfo.Name, propertyInfo.PropertyType));
                property.SetSetMethod(BuildSetProperty(proxy, type, propertyInfo.Name, propertyInfo.PropertyType));
            }
     
            return mappings[type] = proxy.CreateType();
        }
     
     
        public static MethodBuilder BuildSetProperty(TypeBuilder type, Type baseType, string propertyName, Type propertyType)
        {
            MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
            MethodBuilder method = type.DefineMethod("set_" + propertyName, methodAttributes);
     
            MethodInfo method1 = baseType.GetMethod("set_" + propertyName,
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                null,
                new Type[]{ propertyType },
                null
                );
            MethodInfo method2 = typeof(Entity).GetMethod("RaisePropertyChanged",
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                null,
                new Type[]{ typeof(String) },
                null
                );
     
            method.SetReturnType(typeof(void));
            method.SetParameters(propertyType);
     
            ParameterBuilder value = method.DefineParameter(1, ParameterAttributes.None, "value");
     
            ILGenerator gen = method.GetILGenerator();
     
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Call, method1);
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldstr, propertyName);
            gen.Emit(OpCodes.Call, method2);
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ret);
            return method;
        }
     
        public static MethodBuilder BuildGetProperty(TypeBuilder type, Type baseType, string propertyName, Type propertyType)
        {
            MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
            MethodBuilder method = type.DefineMethod("get_" + propertyName, methodAttributes);
     
            MethodInfo method1 = baseType.GetMethod("get_" + propertyName,
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                null,
                new Type[]{ },
                null
                );
     
            method.SetReturnType(propertyType);
            ILGenerator gen = method.GetILGenerator();
            Label label10 = gen.DefineLabel();
     
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Call, method1);
            gen.Emit(OpCodes.Stloc_0);
            gen.Emit(OpCodes.Br_S, label10);
            gen.MarkLabel(label10);
            gen.Emit(OpCodes.Ldloc_0);
            gen.Emit(OpCodes.Ret);
            return method;
        }
    }
    Bon pour le moment j'ai une erreur qu'il faut que je creuse mais je pense que je vais dans le bon sens... Car avec une génération de type mes proxy peuvent être instanciés de façon "standard" et donc je peux faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    AutoMapper.Mapper.CreateMap(typeof(Todo), Proxy.GetProxyType<Todo>());
     
    ...
     
    AutoMapper.Mapper.Map(todoObject, typeof(Todo), Proxy.GetProxyType<Todo>());
    Et Automapper se chargera du (lourd) travail de mapping et parcours de mes graphes d'objet ! (enfin j'espère !)

    Pour le moment mon erreur a lieu sur mon CreateType() de mon TypeBuilder :

    System.TypeLoadException was unhandled by user code
    Message=La déclaration référencée dans une implémentation de méthode ne peut pas être une méthode finale. Type*: 'TodoProxy'. Assembly*: 'ObjectProxies, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
    StackTrace:
    à System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
    à System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
    à System.Reflection.Emit.TypeBuilder.CreateType()
    à Arch.Poc.Silverlight.Models.Proxy.GetProxyType(Type type)
    à Arch.Poc.Silverlight.Models.Proxy.GetProxyType[T]()
    à Arch.Poc.Silverlight.Models.LinFuTest.CustomProxyFormatter..ctor(IClientMessageFormatter actual)
    à Arch.Poc.Silverlight.Models.LinFuTest.CustomOperationFormatterBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
    à System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, IDispatchRuntime dispatch)
    à System.ServiceModel.Description.DispatcherBuilder.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime)
    à System.ServiceModel.Description.DispatcherBuilder.BuildProxyBehavior(ServiceEndpoint serviceEndpoint, BindingParameterCollection& parameters)
    à System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint serviceEndpoint)
    à System.ServiceModel.ChannelFactory.CreateFactory()
    à System.ServiceModel.ChannelFactory.OnOpening()
    à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
    à System.ServiceModel.ChannelFactory.EnsureOpened()
    à System.ServiceModel.ClientBase`1.ChannelBase`1..ctor(ClientBase`1 client)
    à Arch.Poc.Silverlight.CategoryService.CategoryServiceClient.CategoryServiceClientChannel..ctor(ClientBase`1 client)
    à Arch.Poc.Silverlight.CategoryService.CategoryServiceClient.CreateChannel()
    à System.ServiceModel.ClientBase`1.get_Channel()
    à Arch.Poc.Silverlight.CategoryService.CategoryServiceClient.Arch.Poc.Silverlight.CategoryService.ICategoryService.BeginFind(AsyncCallback callback, Object asyncState)
    à Arch.Poc.Silverlight.CategoryService.CategoryServiceClient.OnBeginFind(Object[] inValues, AsyncCallback callback, Object asyncState)
    à System.ServiceModel.ClientBase`1.InvokeAsync(BeginOperationDelegate beginOperationDelegate, Object[] inValues, EndOperationDelegate endOperationDelegate, SendOrPostCallback operationCompletedCallback, Object userState)
    InnerException:
    Bon pour le moment je vois pas le problème va falloir que je creuse encore un peu ...

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 559
    Par défaut
    Bon j'ai réussi !

    En fait le problème venais de mon champ Id de ma classe Entity<T> qui n'est pas virtual ...
    Heureusement les messages d'erreur de TypeBuilder sont clairs

    Bon il me reste plus qu a faire mon mapping "DTO" => Proxy et Proxy => "DTO"

    Pffiuuuu je vois presque le bout !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 09/12/2008, 09h57
  2. Centrer verticalement les objet dans un flow layout ?
    Par Djobird dans le forum Agents de placement/Fenêtres
    Réponses: 1
    Dernier message: 05/09/2008, 09h08
  3. Ou ranger les objets dans Python ?
    Par LLEJEUNE1 dans le forum Général Python
    Réponses: 15
    Dernier message: 24/06/2008, 11h58
  4. Intercepter les click dans un XLA
    Par Bevan dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 25/05/2008, 14h53
  5. [SimpleXML] Intercepter les warning dans simplexml_load_file
    Par lenwil dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 24/01/2008, 14h42

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