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

C# Discussion :

Classe => Un même objet de 2 types différents


Sujet :

C#

  1. #1
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 064
    Points : 420
    Points
    420
    Par défaut Classe => Un même objet de 2 types différents
    Bonjour @ tous,

    Je travaille avec des API REST en JSON en ce moment et un truc m'échappe.
    Pour un même objet (scopes d'un groupe dans mon cas), le GET ne me renvoie pas la même structure que ce qu'attend le POST.

    En gros, lorsque je fait un GET de mon groupe, le serialise met les scopes liés sous forme d'objet name / value, donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        [DataContract]
        public class tblGroup {
    ...
            [DataMember]
            public ObservableCollection<tblScope> scopes { get; set; } // Permissions
    ...
    }
    Mais lors du POST, il attend les scopes sous forme de tableau de string :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        [DataContract]
        public class tblGroup {
    ...
            [DataMember]
            public List<string> scopes { get; set; }
    ...
    }
    Perso, ça m’ennuie de faire 2 classes pour le même objet (car l'API donne et attend l'objet sous le même nom, je ne peux pas tricher).

    Comment faitre ça proprement ?

    Cordialement.
    David.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2007
    Messages
    871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2007
    Messages : 871
    Points : 1 498
    Points
    1 498
    Par défaut
    Salut,

    Il doit il y avoir un moyen de definir le contrat de serialisation pour un champ speficique par exemple: http://blogs.msdn.com/b/carlosfiguei...urrogates.aspx
    Sinon il y a peut etre un type quie correspond a la fois au get et post.


    Tiens-nous au courant, je suis curieux de savoir la solution.

  3. #3
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Une fois que tu as ajouté la référence de service, dans ses options tu peux choisir le type à utiliser pour les collections et pour les dictionnaires. Par défaut ca utilise System.Array pour les collections.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  4. #4
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 064
    Points : 420
    Points
    420
    Par défaut
    Bonjour Mermiche.

    J'ai fait une solution caca (je suis curieux de voir ne nombre de réponse sur la recherche de ce mot clé sur ce site ;-) )
    En fait, j'ai déclaré un tableau de string dans ma classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            [DataMember]
            public ObservableCollection<tblScope> scopes { get; set; }
            [DataMember]
            public List<string> scopesApi { get; set; }
    Et ensuite, lors de l'envoi des données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                scopesApi = (from c in scopes select c.value).ToList(); // Remplir le tableau avec les valeurs de l'objet scope.
                string postData = clsUtils.ObjectToJson<tblGroup>(this); // Sérialise l'objet
                postData = postData.Replace("\"scopes\"", "\"scopesOld\"").Replace("\"scopesApi\"", "\"scopes\""); // Changer le nom des variables car le PUT attends les scopes en tableau de string.
    Ça fonctionne (l'API ne prend que ce qui la concerne), c'est assez fiable (nom délimités par des guillemets) et ça ne prend pas trop de lignes de code (il faut que je le fasse pour presque toutes mes classe).
    Par contre, c'est moche dans le concept (nom des variables en statique) et pas optimisé (envoi de plus de données que besoin).

    Je vais regarder ton lien, pour voir si il y a moyen de faire quelque chose de mieux. Merci.

    Si quelqu'un veut apporter ses lumières... :-)
    David.

  5. #5
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 064
    Points : 420
    Points
    420
    Par défaut
    Bonjour Matt,

    Je ne sais pas ce qu'est une référence de service... Je ne fait pas du WCF, juste un appel à une API via :
    (HttpWebRequest)WebRequest.Create(url)
    Sinon, ce n'est que pour certaines propriétés que je veux de l'array, pas en général (et il faut une règle de mappage car c'est un objet complexe à mettre en string).
    Peux tu me donner plus d'infos, STP ?

    PS: 43 réponses pour "caca", on doit s'inquiéter ou ça doit me rassurer ? ;-)
    David.

  6. #6
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Une référence de service ca permet de générer un proxy automatiquement grâce au WSDL du Web Service. Mais il existe d'autre moyens de procéder, comme tu le fais par exemple.

    Le fait de configurer la référence de service pour utiliser un type de collection plutôt qu'un autre aura pour effet de l'appliquer sur l'ensemble du proxy. Or comme tu viens de préciser que tu ne souhaites personnaliser que quelques propriétés, je pense que ca n'aurait pas fait l'affaire ! La solution de Mermiche est plus adaptée à ton scénario.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  7. #7
    Membre averti Avatar de dacid
    Homme Profil pro
    Inscrit en
    Juin 2003
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 064
    Points : 420
    Points
    420
    Par défaut
    Mermich,

    J'ai exploité ta solution en la simplifiant au maximum :
    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
            /// <summary>Classe contrat de sérialisation http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx </summary>
            public class MyGroupSurrogate : IDataContractSurrogate {
     
                public Type GetDataContractType(Type type) { // var dcs = new DataContractJsonSerializer(typeof(tblGroup), null, int.MaxValue, false, new MyGroupSurrogate(), false); // En Json
                    if (type == typeof(ObservableCollection<tblScope>)) {
                        return typeof(List<string>);
                    } else
                        return type;
                }
     
                public object GetDeserializedObject(object obj, Type targetType) { // object newFamily = dcs.ReadObject(ms);
                    //if (obj is List<string>) { }
                    return obj;
                }
     
                public object GetObjectToSerialize(object obj, Type targetType) { // dcs.WriteObject(ms, this);
                    if (obj is ObservableCollection<tblScope>) {
                        List<string> serializablePerson = (from c in (ObservableCollection<tblScope>)obj select c.value).ToList();
                        return serializablePerson;
                    } else
                        return obj;
                }
     
                public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) { throw new NotSupportedException("unused"); }
                public object GetCustomDataToExport(Type clrType, Type dataContractType) { throw new NotSupportedException("unused"); }
                public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) { throw new NotSupportedException("unused"); }
                public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { throw new NotSupportedException("unused"); }
                public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) { throw new NotSupportedException("unused"); }
            }
    ...
                //var dcs = new DataContractSerializer(typeof(tblGroup), null, int.MaxValue, false, false, new MyGroupSurrogate()); // En Xml
                var dcs = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(tblGroup), null, int.MaxValue, false, new MyGroupSurrogate(), false); // En Json
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                dcs.WriteObject(ms, this);
                string postData = Encoding.UTF8.GetString(ms.ToArray());
    Ça fonctionne, c'est extra... Merci pour le lien. :-)

    Et merci Matt pour tes éclaircissements.

    [EDIT 1]
    Aie,

    Comme ca fonctionne très bien pour le POST, je me suis dit "Autant l'utiliser pour le GET".
    Du coup, ca ne va plus car il ne faut plus caster le tblScope en List<string> du coup.
    Or, pour GetDeserializedObject comme pour GetObjectToSerialize, il passe par GetDataContractType qui fait la transformation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
            public Type GetDataContractType(Type type) { // var dcs = new DataContractJsonSerializer(typeof(tblGroup), null, int.MaxValue, false, new MyGroupSurrogate(), false); // En Json
                if (type == typeof(ObservableCollection<tblScope>)) {
                    return typeof(List<string>);
                } else
                    return type;
            }
    Il n'y a pas moyen de voir si on est dans un sens ou dans l'autre ?

    [EDIT 2]
    Bon, j'ai du tricher en surchargeant le constructeur.
    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
        /// <summary>Classe contrat de sérialisation http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx </summary>
        public class MyGroupSurrogate : IDataContractSurrogate {
     
            private bool toSerialise;
     
            public MyGroupSurrogate(bool pToSerialise) { toSerialise = pToSerialise; }
            public Type GetDataContractType(Type type) { // var dcs = new DataContractJsonSerializer(typeof(tblGroup), null, int.MaxValue, false, new MyGroupSurrogate(), false); // En Json
                if ((toSerialise) && (type == typeof(ObservableCollection<tblScope>))) {
                    return typeof(List<string>);
                } else
                    return type;
            }
     
            public object GetDeserializedObject(object obj, Type targetType) { // object newFamily = dcs.ReadObject(ms);
                //if (obj is List<string>) { }
                return obj;
            }
     
            public object GetObjectToSerialize(object obj, Type targetType) { // dcs.WriteObject(ms, this);
                if (obj is ObservableCollection<tblScope>) {
                    List<string> serializablePerson = (from c in (ObservableCollection<tblScope>)obj select c.value).ToList();
                    return serializablePerson;
                } else
                    return obj;
            }
    Ca fonctionne, mais du coup, je ne peux plus utiliser le même objet pour serialiser et deserialiser.
    David.

Discussions similaires

  1. Réponses: 5
    Dernier message: 10/08/2014, 08h41
  2. Réponses: 8
    Dernier message: 12/01/2011, 19h00
  3. Réponses: 42
    Dernier message: 23/12/2010, 20h58
  4. Réponses: 3
    Dernier message: 24/06/2009, 21h08
  5. Réponses: 2
    Dernier message: 29/05/2009, 14h52

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