2008-11-01 3 views
7

Das ist eine sehr komplizierte Frage, die angibt, wie Daten über einen Webdienstaufruf serialisiert werden, wenn die Daten nicht stark typisiert werden. Ich werde versuchen, es so gut wie möglich auszulegen.Serialisierung von Name/Wert-Paaren in einem benutzerdefinierten Objekt über Webdienst

Probenlagerung Objekt:

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

Beispiel zu verwenden:

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

Rückgabewert von Web Service:

<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> 

Was ich will:

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

The Reason & Other Stuff:

Zuerst tut mir leid für die Länge der Post, aber ich wollte auch reproduzierbar Code geben.

Ich möchte es in diesem Format, weil ich die Webdienste von PHP konsumiere. Ich mag einfach gehen:

// Das ist imporant

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

Wenn es in dem anderen Format ist, dann gäbe es keine Möglichkeit für mich, das zu erreichen, überhaupt nicht. IS

// DIESE imporant

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

Leider bin ich nicht sicher, wie dies zu tun: in C# Außerdem, wenn ich den Dienst am raubend, würde ich auch folgendes tun möchte in der Lage sein, . Ich konnte es auf diese Weise erreichen, indem ich ein benutzerdefiniertes Dictionary erstellte, das IXmlSerializer (siehe StackOverflow: IXmlSerializer Dictionary) implementierte, jedoch das WSDL-Schema aus dem Wasser löste. Es ist auch viel zu kompliziert und hat schreckliche Ergebnisse in meiner WinFormsTester Anwendung erzeugt!

Gibt es eine Möglichkeit, dies zu erreichen? Welche Art von Objekten muss ich erstellen? Gibt es eine Möglichkeit, dies zu tun/anders als durch eine stark typisierte Sammlung /? Natürlich, wenn ich es stark typisierte wie diese machen:

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

Dann wäre es perfekt funktionieren, würde ich keine WSDL Probleme haben, ich wäre in der Lage sein, einen einfachen Zugriff auf sie von PHP und C# (.OtherInfo.Hobbies) .

Allerdings würde ich den Punkt der NVP völlig verlieren, in dem ich im Voraus wissen müsste, was die Liste ist, und es wäre unveränderbar .. sagen wir, aus einer Datenbank.

Danke an alle !! Ich hoffe, wir können hier eine Lösung finden.Hier sind die Anforderungen wieder:

  1. WSDL-Schema nicht
  2. Name des Wert-Paare brechen sollte (NVP ist) sollte in Attribut-Format serialisiert werden
  3. Sollte einfach namentlich NVP ist in PHP für den Zugriff auf [ "Hobby"]
  4. Sollte für den Zugriff in C# leicht sein (und kompatibel sein mit ihm Generator Proxy ist)
  5. leicht sein serializable
  6. mich benötigen dringend die Daten eingeben

Jetzt bin ich/vollständig/offen auf eine bessere/andere Weise zu tun, dies zu tun. Ich speichere einige relativ "statische" Informationen (wie Name) und eine Menge Daten. Wenn es einen besseren Weg gibt, würde ich es gerne hören.

Antwort

5

Dies ist wie dynamische Eigenschaften für ein Objekt. C# ist im Gegensatz zu JavaScript keine dynamische Sprache oder PHP kann die Objekteigenschaften im Handumdrehen parsen. Die folgenden zwei Methoden sind, was ich mir vorstellen kann. Die zweite könnte in Ihre Anforderungen passen.

Die KISS Way

Die Keep It Dummerweise

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

Sie einfach Name Wert-Paare haben kann, die durch getrennt ist '|'

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

serialisierten Formen

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

Die dynamische Art und Weise in C#

das Paar Teil-Marke Name Wert ein XML-Element werden, so dass Sie es dynamisch aufbauen können.

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

Sie können ganz einfach aufbauen Otherinfo Objekt als Element centric z.B.

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

Die serialisierte Form wird es

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

oder bauen sein als

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> 

Für jede dynamische Sprache centric Attribut, es direkt auf die Eigenschaften zugreifen können. Im übrigen können sie auf den Wert zugreifen, indem sie das XML lesen. Das Lesen von XML wird vom Großteil des Frameworks gut unterstützt.

+0

Danke !! Beide sind großartige Ideen, ich Ich denke, dass ich mit einer dieser Lösungen arbeiten kann, um meine Ziele zu erreichen. "Gute Arbeit am XElement, darüber hätte ich nicht nachgedacht (Mangel an k darüber nachzudenken. : P). –

+0

Es wäre interessanter, wenn Sie anfangen, JSON für Javascript zu behandeln. –

-1

Ich bin mir nicht sicher, das würde Ihr Problem lösen (es wäre in C#, aber vielleicht nicht in PHP), aber versuchen Sie Dictionary<string,List<string>> OtherInfo anstelle von List<NameValuePairs>. Dann wären "Hobbies" und "Websites" Ihre Schlüssel und die Werte wären die Liste der Hobbies oder Websites. Ich bin mir nicht sicher, wie es serialisieren würde.

würden Sie in der Lage sein, die Listen von Hobbys zu verweisen, wie:

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

[EDIT] here für einen generischen XML serializable Dictionary. Diese abgeleitete Klasse ist diejenige, die Sie anstelle des generischen Dictionary verwenden müssten.

+0

Sie können eine Dicationry nicht über XML serialisieren :(Vielen Dank! –

+0

Das Wörterbuch ist serialisierbar, wenn Sie davon abgeleitet sind und die abgeleitete Klasse als serialisierbar markieren. Http://cs.rthand.com/blogs/blog_with_righthand/ archive/2005/08/06/How-to-Deserialize-a-Dictionary_3C00_TKey_2C00_-TValue_3E00_-abcendant-using-binary-formatter.aspx – tvanfosson

+0

Wie auch immer Sie Dictionary in WCF serialisieren, der datacontractSerializer –

0

Sehen Sie sich das System.Xml.Serialization.XmlSerializerAssemblyAttribute-Attribut an. Auf diese Weise können Sie einen benutzerdefinierten Serializer auf Klassenebene angeben. Sie können XML ausspucken, was Ihnen gefällt.

Ein schneller Weg, um auf diese zu beschleunigen, ist sgen.exe zu verwenden, um einen zu generieren und einen Blick darauf mit Reflector zu werfen.

-Oisin

1

Als eine völlig andere Einstellung, warum nicht darüber nachdenken, es komplett anders zu machen. Verfügen über eine Webdienstmethode, um das serialisierte Speicherobjekt abzüglich der OtherInfo und eine andere Methode zurückzugeben, um die Liste der Eigenschaften (Schlüssel) für OtherInfo zurückzugeben, und eine dritte, um die Liste der Werte für einen beliebigen Schlüssel zurückzugeben. Zugegeben, es werden mehr Rundreisen zum Webservice benötigt, wenn Sie alle Daten wünschen, aber die Lösung wird viel einfacher und flexibler.

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

Das ist eine interessante Idee !! Ich bin mir nicht sicher, ob es eine gute Lösung für das ist, woran ich gerade arbeite, aber ich sehe, dass es eine andere Art zu denken ist, und es ist definitiv eine Lösung. Danke/tvanfosson /. –

4

Darauf habe ich mich festgelegt.

Klassenstruktur:

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

Verbrauch:

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

Ausgang:

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

Ich mag würde allen für ihre Unterstützung danken, ich schätze die Hilfe und Ideen.