2012-07-03 9 views
5

Estoy intentando serializar objetos con la biblioteca ServiceStack.Text. Esto funcionaSerializando ExpandoObject con ServiceStack.Text

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

consigo, como espero

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

Sin embargo

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

llego a mi sorpresa

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

Por qué! ¿Que esta pasando?

En segundo lugar, ¿cómo puedo obtener lo que quiero?

+0

Parece que el serializador está malinterpretando su estructura de datos ... ¿podría publicar la estructura? –

+0

Si instala ServiceStack.Text, debería poder ejecutar mi código arriba (repitiendo las instrucciones using). –

Respuesta

5

ExpandoObject implementa IConnection<KeyValuePair> y IEnumerable<KeyValuePair>:

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

Mi conjetura es que internamente, el serializador ServiceStack está tratando el ExpandoObject como IEnumerable<KeyValuePair>, y por lo que serializa a una matriz JSON de pares clave/valor.


Esto difiere de la primera (de trabajo) fragmento de código .NET, porque en realidad construye una verdadera clase (anónimo) para sus datos, básicamente se hace:

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

de forma automática, por lo que cuando se se envía al serializador, está trabajando con una clase real con propiedades reales, mientras que el ExpandoObject está realmente respaldado por un object[] internamente.


En una nota lateral, de Microsoft System.Web.Helpers.Json se comporta de la misma manera. Esta prueba pasa:

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

Una edición final:

Puede que esto funcione de la manera deseada por convertir su ExpandoObject en un Dictionary<string, object>. La advertencia de este código es que duplica los datos en un diccionario, por lo que tiene 2 copias en la memoria (o un poco menos que, ya que técnicamente las cadenas podrían estar internados).

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

Aunque, para cualquier persona que viene a través de esta tarde, y es en realidad el uso System.Web.Helpers.Json, mejor que puede hacer es simplemente envolver su ExpandoObject en un DynamicJsonObject así:

[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 vez que trabajé a través de eso, encontré una pregunta similar aquí: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

+0

Gracias Rally, esto tiene sentido. ¿Alguna idea de cómo serializar ExpandoObject de la manera que quiero? –

+0

Lamentablemente, no, yo no. Intenté 'System.Web.Helpers.Json' con la esperanza de que funcionara como querías, y lo iba a proponer como alternativa, pero hace lo mismo. :) – CodingWithSpike

+0

@MattHickford - rayar mi comentario anterior. Agregué una posible solución al final de mi respuesta. – CodingWithSpike

Cuestiones relacionadas