Question

Il s'agit d'une question très complexe concernant la sérialisation des données via un appel de service Web, lorsque les données ne sont pas fortement typées. Je vais essayer de l'exposer le mieux possible.

Exemple d'objet de stockage:

[Serializable]
public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public List<NameValuePairs> OtherInfo { get; set; }  
}
[Serializable]   
public class NameValuePairs {
  public string Name { get; set; }
  public string Value { get; set; }
}

Exemple d'utilisation:

[WebMethod]
    public List<StorageObject> GetStorageObjects() {
      List<StorageObject> o = new List<StorageObject>() {
        new StorageObject() { 
          Name = "Matthew",
          Birthday = "Jan 1st, 2008", 
          OtherInfo = new List<NameValuePairs>() {
            new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
            new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
          }
        },
        new StorageObject() { 
          Name = "Joe",
          Birthday = "Jan 10th, 2008",
          OtherInfo = new List<NameValuePairs>() { 
            new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
            new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
          }
        }
      };

      return o;
    }

Valeur renvoyée par le service Web:

<StorageObject>
    <Name>Matthew</Name>
    <Birthday>Jan 1st, 2008</Birthday>
    <OtherInfo>
        <NameValuePairs>
            <Name>Hobbies</Name>
            <Value>Programming</Value>
        </NameValuePairs>
        <NameValuePairs>
            <Name>Website</Name>
            <Value>Stackoverflow.com</Value>
        </NameValuePairs>
    </OtherInfo>
</StorageObject>

Ce que je veux:

<OtherInfo>
    <Hobbies>Programming</Hobbies>
    <Website>Stackoverflow.com</Website>
</OtherInfo>

The Reason & Autres choses:

Tout d'abord, je suis désolé pour la longueur du message, mais je voulais aussi donner un code reproductible.

Je le veux dans ce format, car je consomme les services Web de PHP. Je veux aller facilement:

// CECI EST IMPORANT

In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".  

Si c'est dans l'autre format, il n'y aurait aucun moyen pour moi d'y parvenir. De plus, si je consomme le service en C #, j'aimerais également pouvoir effectuer les opérations suivantes:

// CECI EST IMPORANT

In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];

Malheureusement, je ne sais pas comment y parvenir. J'ai pu l'obtenir de cette façon en construisant un dictionnaire personnalisé qui implémentait IXmlSerializer (voir StackOverflow: Dictionnaire IXmlSerializer ) cependant, il a vidé le schéma WSDL de l’eau. C’est aussi beaucoup trop compliqué et cela a produit des résultats horribles dans mon application WinFormsTester!

Y a-t-il un moyen d'accomplir cela? Quel type d'objets dois-je créer? Est-il possible de faire ceci / autrement qu'en faisant une collection fortement typée /? Évidemment, si je le fais fortement typé comme ceci:

public class OtherInfo {
  public string Hobbies { get; set; }
  public string FavoriteWebsite { get; set; }
}

Ensuite, cela fonctionnerait parfaitement, je n’aurais aucun problème WSDL, je pourrais facilement y accéder depuis PHP et C # (.OtherInfo.Hobbies).

Cependant, je perdrais complètement le sens des NVG, dans la mesure où je devrais connaître à l’avance la liste, qui ne serait pas modifiable, par exemple, dans une base de données.

Merci à tous !! J'espère que nous pourrons trouver une solution à ce problème. Voici à nouveau les conditions requises:

  1. Le schéma WSDL ne doit pas être rompu
  2. Les paires nom / valeur (NVP) doivent être sérialisées au format d'attribut
  3. Doit être facile d’accéder aux NVP en PHP par nom [" Hobbies "]
  4. Doit être facile d'accès en C # (et compatible avec son générateur de proxy)
  5. Soyez facilement sérialisable
  6. Pas besoin que je tape fortement les données

Maintenant, je suis / complètement / ouvert (e) à entrer dans une manière meilleure / différente de le faire. Je stocke des données relativement & "; Statiques &"; informations (comme Nom), et un tas de données. S'il existe un meilleur moyen, j'aimerais l'entendre.

Était-ce utile?

La solution

Cela ressemble aux propriétés dynamiques d'un objet. C # n'est pas un langage dynamique contrairement à JavaScript ou peut-être que PHP peut analyser les propriétés de l'objet à la volée. Les deux méthodes suivantes sont ce que je peux penser. Le second peut s’adapter à vos besoins.

La voie des bisous

La manière stupide de garder les choses simples

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public List<string> OtherInfo { get; set; }  
}

Vous pouvez avoir des paires nom / valeur séparées par '|'

OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}

Formulaires sérialisés

<StorageObject>
    <Name>Matthew</Name>
    <Birthday>Jan 1st, 2008</Birthday>
    <OtherInfo>
        <string>Hobbies|Programming</string>
        <string>Website|Stackoverflow.com</string>
    </OtherInfo>
</StorageObject>

La manière dynamique en C #

Faites de la paire paire nom-valeur un élément XML pour pouvoir la construire dynamiquement.

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}

Vous pouvez facilement construire l'objet OtherInfo en tant qu'élément centré par exemple.

XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);

Le formulaire sérialisé sera

<OtherInfo>
    <Hobbies>Programming</Hobbies>
    <Website>Stackoverflow.com</Website>
</OtherInfo>

ou construisez-le en tant qu'attribut centrique

XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..nvp xattribute Hobbies & value..);
OtherInfo.Add( ..nvp xattribute WebSite & value..);

<OtherInfo>
    <nvp n="Hobbies" v="Programming" />
    <nvp n="Website" v="Stackoverflow.com" />
</OtherInfo>

Pour tout langage dynamique, il peut accéder directement aux propriétés. Pour le reste, ils peuvent accéder à la valeur en lisant le XML. La lecture de XML est bien supportée par la plupart des frameworks.

Autres conseils

C'est ce sur quoi je me suis installé.

Structure de classe:

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  [XmlAnyElement("Info")]  // this prevents double-nodes in the XML
  public XElement OtherInfo { get; set; }
}

Utilisation:

StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");

Sortie:

<Info>
  <Hobbies>Programming</Hobbies>
  <Website>Stackoverflow.com</Website>
</Info>

Je voudrais remercier tout le monde pour leur aide, j'apprécie vraiment l'aide et les idées.

Comme cela est complètement différent, pourquoi ne pas penser à le faire complètement différemment. Disposez d'une méthode de service Web pour renvoyer l'objet de stockage sérialisé, moins le OtherInfo, d'une autre méthode pour renvoyer la liste des propriétés (clés) de <=>, et d'une troisième pour renvoyer la liste des valeurs de toutes les clés. Certes, il faudra plus d'allers-retours vers le service Web si vous souhaitez disposer de toutes les données, mais la solution sera beaucoup plus simple et plus flexible.

[Serializable]
public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }

  [Nonserializable]
  public Dictionary<string,List<string>> OtherInfo { get; set; }  
}

[WebMethod]
public List<StorageObject> GetStorageObjects() {
    // returns list of storage objects from persistent storage or cache
}

[WebMethod]
public List<string> GetStorageObjectAttributes( string name )
{
    // find storage object, sObj
    return sObj.Keys.ToList();
}

[WebMethod]
public List<string> GetStorageObjectAtributeValues( sting name, string attribute )
{
    // find storage object, sObj
    return sObj[attribute];
}

Consultez l'attribut System.Xml.Serialization.XmlSerializerAssemblyAttribute. Cela vous permet de spécifier un sérialiseur de niveau classe personnalisé. Vous serez capable de cracher tout le XML que vous aimez.

Un moyen rapide de s’y habituer consiste à utiliser sgen.exe pour en générer un et y jeter un coup d’œil avec Reflector.

-Oisine

Je ne suis pas sûr que cela résoudrait votre problème (cela se ferait en C #, mais peut-être pas en PHP), mais essayez d'utiliser Dictionary<string,List<string>> OtherInfo au lieu de List<NameValuePairs>. Ensuite, & Quot; Hobbies & Quot; et " Sites Web " seraient vos clés et les valeurs seraient la liste des loisirs ou des sites Web. Je ne suis toutefois pas sûr de la façon dont cela serait mis en série.

Vous pourrez référencer les listes de loisirs comme suit:

List<string> hobbies = storageObject.OtherInfo["Hobbies"];

[EDIT] Voir ici pour une dictionnaire générique XML sérialisable. Cette classe dérivée est celle que vous auriez besoin d’utiliser à la place du dictionnaire générique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top