Serializzazione di coppie nome / valore in un oggetto personalizzato tramite servizio Web
-
05-07-2019 - |
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:
- Lo schema WSDL non dovrebbe rompersi
- Le coppie nome-valore (NVP) devono essere serializzate nel formato degli attributi
- Dovrebbe essere facile accedere agli NVP in PHP per nome [" Hobby "]
- Dovrebbe essere di facile accesso in C # (ed essere compatibile con il suo generatore Proxy)
- Sii facilmente serializzabile
- 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.
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.