Domanda

Questa è una domanda molto complicata su come serializzare i dati tramite una chiamata al servizio Web, quando i dati non sono fortemente digitati. Proverò a disporlo nel miglior modo possibile.

Oggetto di archiviazione di esempio:

[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; }
}

Esempio di utilizzo:

[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;
    }

Valore di ritorno dal servizio 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>

Quello che voglio:

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

The Reason & amp; Altre cose:

Per prima cosa, mi dispiace per la lunghezza del post, ma volevo anche fornire un codice riproducibile.

Lo voglio in questo formato, perché sto consumando i servizi web da PHP. Voglio andare facilmente:

// QUESTO È IMPORTANTE

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

Se è nell'altro formato, allora non ci sarebbe alcun modo per farlo. Inoltre, in C # se sto utilizzando il servizio, vorrei anche essere in grado di fare quanto segue:

// QUESTO È IMPORTANTE

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

Sfortunatamente, non sono sicuro di come riuscirci. Sono stato in grado di farlo in questo modo, costruendo un dizionario personalizzato che implementava IXmlSerializer (vedi StackOverflow: IXmlSerializer Dictionary ), tuttavia, ha espulso lo schema WSDL dall'acqua. È anche troppo complicato e ha prodotto risultati orribili nella mia applicazione WinFormsTester!

C'è un modo per raggiungere questo obiettivo? Che tipo di oggetti devo creare? C'è un modo per fare questo / diverso da quello di creare una raccolta fortemente tipizzata /? Ovviamente, se lo faccio fortemente scritto in questo modo:

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

Quindi funzionerebbe perfettamente, non avrei problemi con WSDL, sarei in grado di accedervi facilmente da PHP e C # (.OtherInfo.Hobbies).

Tuttavia, perderei completamente il punto di NVP, in quanto dovrei sapere in anticipo quale sia l'elenco, e sarebbe immutabile .. diciamo, da un database.

Grazie a tutti !! Spero che siamo in grado di trovare una sorta di soluzione a questo. Ecco di nuovo i requisiti:

  1. Lo schema WSDL non dovrebbe rompersi
  2. Le coppie nome-valore (NVP) devono essere serializzate nel formato degli attributi
  3. Dovrebbe essere facile accedere agli NVP in PHP per nome [" Hobby "]
  4. Dovrebbe essere di facile accesso in C # (ed essere compatibile con il suo generatore Proxy)
  5. Sii facilmente serializzabile
  6. Non mi impone di digitare con forza i dati

Ora, sono / completamente / aperto all'input su un modo migliore / diverso per farlo. Sto memorizzando alcuni & Quot; statici & Quot; informazioni (come Nome) e un mucchio di dati. Se c'è un modo migliore, mi piacerebbe ascoltarlo.

È stato utile?

Soluzione

Questo è come proprietà dinamiche per un oggetto. C # non è un linguaggio abbastanza dinamico a differenza di JavaScript o forse PHP può analizzare le proprietà dell'oggetto al volo. I seguenti due metodi sono ciò a cui riesco a pensare. Il secondo potrebbe adattarsi alle tue esigenze.

The KISS Way

Il modo stupido di Keep It Simple

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

Puoi avere coppie nome-valore separate da '|'

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

Moduli serializzati

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

Il modo dinamico in C #

Trasforma la parte della coppia valore-nome in un elemento XML in modo da poterlo costruire dinamicamente.

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

Puoi facilmente costruire un oggetto OtherInfo come centrato sull'elemento per esempio.

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

Il modulo serializzato sarà

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

o crealo come incentrato sugli attributi

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>

Per qualsiasi linguaggio dinamico, può accedere direttamente alle proprietà. Per il resto, possono accedere al valore leggendo l'XML. La lettura di XML è ben supportata dalla maggior parte del framework.

Altri suggerimenti

Questo è ciò su cui ho deciso.

Struttura della 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; }
}

Utilizzo:

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

Output:

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

Vorrei ringraziare tutti per l'assistenza, apprezzo molto l'aiuto e le idee.

In una prospettiva completamente diversa, perché non pensare di farlo in modo completamente diverso. Utilizzare un metodo del servizio Web per restituire l'oggetto di archiviazione serializzato, meno OtherInfo e un altro metodo per restituire l'elenco di proprietà (chiavi) per <=> e un terzo per restituire l'elenco di valori per qualsiasi chiave. Certo, ci vorranno più viaggi di andata e ritorno al servizio web se si desidera tutti i dati, ma la soluzione sarà molto più semplice e flessibile.

[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];
}

Dai un'occhiata all'attributo System.Xml.Serialization.XmlSerializerAssemblyAttribute. Ciò consente di specificare un serializzatore di livello classe personalizzato. Sarai in grado di sputare qualunque XML ti piaccia.

Un modo rapido per aggiornarsi su questi è usare sgen.exe per generarne uno e dare un'occhiata con Reflector.

-Oisin

Non sono sicuro che questo risolva il tuo problema (sarebbe in C #, ma forse non in PHP), ma prova a usare Dictionary<string,List<string>> OtherInfo invece di List<NameValuePairs>. Quindi & Quot; Hobby & Quot; e " Siti web " sarebbero le tue chiavi e i valori sarebbero la lista di hobby o siti web. Non sono sicuro di come serializzerebbe, però.

Potresti fare riferimento agli elenchi di hobby come:

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

[EDIT] Vedi qui per un dizionario generico serializzabile XML. Questa classe derivata è quella che dovresti usare al posto del Dizionario generico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top