2012-07-03 7 views
5

Ich versuche Objekte mit der Bibliothek ServiceStack.Text serialisieren. Dies funktioniertSerialisierung von ExpandoObject mit ServiceStack.Text

using System.Dynamic; 
using ServiceStack.Text; 
var x = new {Value= 10, Product = "Apples"};     
Console.WriteLine(JsonSerializer.SerializeToString(x)); 

ich, wie ich

{"Value":10,"Product":"Apples"} 

jedoch

dynamic x = new ExpandoObject(); 
x.Value = 100; 
x.Product = "Apples"; 
Console.WriteLine(JsonSerializer.SerializeToString(x)); 

ich zu meiner Überraschung

[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}] 

Warum erwarten! Was ist los?

Zweitens, wie bekomme ich was ich will?

+0

Es sieht so aus, als würde der Serializer Ihre Datenstruktur missverstehen ... könnten Sie die Struktur posten? –

+0

Wenn Sie ServiceStack.Text installieren, sollten Sie meinen Code oben ausführen können (die using-Anweisungen wiederholen). –

Antwort

5

ExpandoObject implementiert IConnection<KeyValuePair> und IEnumerable<KeyValuePair>:

public sealed class ExpandoObject : 
    IDynamicMetaObjectProvider, 
    IDictionary<string, object>, 
    ICollection<KeyValuePair<string, object>>, 
    IEnumerable<KeyValuePair<string, object>>, 
    IEnumerable, INotifyPropertyChanged 

Meine Vermutung, dass intern ist, das ServiceStack Serialisierer die ExpandoObject als IEnumerable<KeyValuePair> behandelt, und so serialisiert es zu einer JSON Array von Schlüssel/Wert-Paaren.


Dies unterscheidet sich von Ihrem ersten (in Betrieb) Code-Schnipsel, weil .NET baut tatsächlich eine echte (anonym) Klasse für Ihre Daten, im Grunde macht es:

public class SomeNameTheCompilerMakesUp { 
    internal int Value { get; set; } 
    internal string Product { get; set; } 
} 

für Sie automatisch, so dass, wenn es Wird an den Serialisierer gesendet, arbeitet es mit einer echten Klasse mit realen Eigenschaften, während die ExpandoObject intern durch eine object[] unterstützt wird.


Auf einer Seite zur Kenntnis, System.Web.Helpers.Json Microsoft verhält sich die gleiche Weise. Dieser Test besteht:

[TestMethod] 
    public void ExpandoObjectSerializesToJsonArray() 
    { 
     dynamic anonType = new { Value = 10, Product = "Apples" }; 

     dynamic expando = new ExpandoObject(); 
     expando.Value = 10; 
     expando.Product = "Apples"; 

     var anonResult = System.Web.Helpers.Json.Encode(anonType); 
     var expandoResult = System.Web.Helpers.Json.Encode(expando); 

     Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", anonResult); 
     Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult); 
    } 

Eine letzte edit:

Sie diese Arbeit den Weg machen können Sie von Ihrem ExpandoObject in eine Dictionary<string, object> drehen. Der Vorbehalt zu diesem Code ist, dass es die Daten in ein Wörterbuch kopiert, also haben Sie 2 Kopien im Gedächtnis (oder etwas weniger als, da technisch die Zeichenketten möglicherweise interniert werden).

[TestMethod] 
    public void TestMethod1() 
    { 
     dynamic expando = new ExpandoObject(); 
     expando.Value = 10; 
     expando.Product = "Apples"; 

     // copy expando properties to dictionary 
     var dictionary = ((ExpandoObject)expando).ToDictionary(x => x.Key, x => x.Value); 

     var expandoResult = System.Web.Helpers.Json.Encode(expando); 
     var dictionaryResult = System.Web.Helpers.Json.Encode(dictionary); 

     Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult); 
     Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult); 
    } 

Obwohl, für jeden, der über diese später kommt, und tatsächlich ist System.Web.Helpers.Json verwenden, desto besser, was zu tun ist, wickeln Sie einfach Ihre ExpandoObject in einem DynamicJsonObject wie folgt aus:

[TestMethod] 
    public void TestMethod1() 
    { 
     dynamic expando = new ExpandoObject(); 
     expando.Value = 10; 
     expando.Product = "Apples"; 

     var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando)); 

     Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult); 
    } 

Ans ich einmal gearbeitet Dadurch habe ich eine ähnliche Frage hier gefunden: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

+0

Danke Rally, das macht Sinn. Irgendeine Idee, wie ich ExpandoObject so serialisieren kann, wie ich es möchte? –

+0

Leider nein, ich nicht. Ich habe 'System.Web.Helpers.Json' probiert, in der Hoffnung, dass es so funktioniert, wie Sie es wollten, und das als Alternative vorschlagen würde, aber es macht dasselbe. :) – CodingWithSpike

+0

@MattHickford - scratch meinen vorherigen Kommentar. Ich fügte eine mögliche Lösung am Ende meiner Antwort hinzu. – CodingWithSpike

Verwandte Themen