Como serializar um tipo anônimo de C # em uma string JSON?

162

Estou tentando usar o seguinte código para serializar um tipo anônimo para JSON:

var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray()); 

No entanto, recebo a seguinte exceção quando isso é executado:

Digite '<> f__AnonymousType1`3 [System.Int32, System.Int32, System.Object []]' não pode ser serializado. Considere marcá-lo com o atributo DataContractAttribute e marcar todos os seus membros que você deseja serializar com o atributo DataMemberAttribute. Consulte a documentação do Microsoft .NET Framework para outros tipos suportados.

Não posso aplicar atributos a um tipo anônimo (tanto quanto eu sei). Existe outra maneira de fazer essa serialização ou estou faltando alguma coisa?

JC Grubbs
fonte

Respostas:

159

Experimente o JavaScriptSerializer em vez do DataContractJsonSerializer

JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);
Nick Berardi
fonte
17
Trackback, parece que foi descontinuado no SP1.
21413 Biswanath
7
para algo tão obsoleto, parece estar sendo usado em muitas novas estruturas da Microsoft, incluindo o MVC. aspnet.codeplex.com/SourceControl/changeset/view/21528#266491
Nick Berardi
1
Como faço para incluir esse projeto no non-asp.net (aplicativo de console)?
Alxandr
4
@Alxandr: Você precisaria fazer referência System.Web.Extensions.dlle adicionar uma using System.Web.Script.Serialization;declaração.
Aleatório
1
O problema @randomgui foi o tipo de saída do projeto definido como perfil do cliente.
Alxandr
75

Como outros já mencionaram, o Newtonsoft JSON.NET é uma boa opção. Aqui está um exemplo específico para serialização JSON simples:

return JsonConvert.SerializeObject(
    new
    {
       DataElement1,
       SomethingElse
    });

Eu achei uma biblioteca muito flexível e versátil.

Matthew Nichols
fonte
14

Você pode experimentar meu ServiceStack JsonSerializer , é o serializador .NET JSON mais rápido no momento. Ele suporta serialização de DataContract, qualquer tipo de POCO, interfaces, objetos com ligação tardia, incluindo tipos anônimos, etc.

Exemplo básico

var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>(); 

Nota: Use o Microsofts JavaScriptSerializer apenas se o desempenho não for importante para você, pois tive que deixá-lo fora dos meus benchmarks, pois é até 40x-100x mais lento que os outros serializadores JSON.

mythz
fonte
7
Estou usando o MS JavaScriptSerializer na pilha MVC3 para serializar objetos com pequenas quantidades de dados. É muito rápido nesses casos, levando menos de um milissegundo para fazer o que eu preciso. A consulta do banco de dados em si leva 50x-100x mais, portanto, não é realmente um gargalo significativo na minha situação.
Brian
2
A otimização prematura é uma ... Bem, você sabe.
Mathias Lykkegaard Lorenzen
1
O link "serializador JSON .NET mais rápido" está 404ing! Além disso, esta resposta tem mais de 5 anos e meio de idade. Você tem uma atualização sobre o desempenho de vários serializadores .NET JSON?
ErikE
11

Observe que isso é de 2008. Hoje eu argumentaria que o serializador deve ser incorporado e que você provavelmente pode usar os atributos swagger + para informar os consumidores sobre seu endpoint e retornar dados.


Eu argumentaria que você não deveria serializar um tipo anônimo . Eu conheço a tentação aqui; você deseja gerar rapidamente alguns tipos descartáveis ​​que serão usados ​​em um ambiente de tipo vagamente conhecido como Javascript no navegador. Ainda assim, eu criaria um tipo real e o decoraria como serializável. Então você pode digitar fortemente seus métodos da web. Embora isso não importe um pingo para Javascript, ele adiciona alguma autodocumentação ao método. Qualquer programador razoavelmente experiente poderá olhar para a assinatura da função e dizer: "Oh, esse é o tipo Foo! Eu sei como isso deve parecer no JSON".

Dito isto, você pode tentar o JSON.Net para fazer a serialização. Eu não tenho idéia se vai funcionar

Jason Jackson
fonte
3
JSON.Net funciona muito bem. Eu diria que você não deveria :), acho que é bastante legítimo em muitos casos.
aprilchild
2
Depois de ver os tipos "jogar fora" sendo usados ​​no MVC, posso ver alguns usos convincentes. Eu acho que é uma ferramenta muito útil para ter em sua caixa de ferramentas .Net.
Matthew Whited
12
Este é um ponto em que também amoleci, especialmente no caso de tipos apenas de consumo. Mas se o objeto estiver retornando ao servidor ou for usado em mais de um local, ainda acredito que a criação de um tipo resultará em menos problemas.
7139 Jason Jackson
A desserialização de estilo DataContract não lida bem com tipos polimórficos. Você precisa escrever seu próprio desserializador. Muita manutenção de código.
Micahhoover 12/01
Um caso de uso em que a serialização de tipos anônimos é útil são os testes de unidade para APIs da web.
24416 howcheng
9

A maneira mais rápida que encontrei foi esta:

var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);

Espaço para nome: System.Web.Script.Serialization.JavaScriptSerializer

i31nGo
fonte
2
E para desserialização:. . dinâmico myObject = JsonConvert.DeserializeObject <dinâmico> (saída); . . Referência: Newtonsoft.json.dll
i31nGo
2

Você poderia usar o Newtonsoft.Json.

var warningJSON = JsonConvert.SerializeObject(new {
                warningMessage = "You have been warned..."
            });
Ahmet Arslan
fonte
1

Supondo que você esteja usando isso para um serviço da Web, basta aplicar o seguinte atributo à classe:

[System.Web.Script.Services.ScriptService]

Em seguida, o seguinte atributo para cada método que deve retornar o Json:

[ScriptMethod(ResponseFormat = ResponseFormat.Json)]

E defina o tipo de retorno para os métodos como "objeto"

Paulo
fonte
Para um serviço Web ASP padrão [ScriptMethod (ResponseFormat = ResponseFormat.Json)] não é necessário no método, [WebMethod] fará. Além disso, você não deve definir o tipo de retorno como objeto, ele pode e deve ser fortemente digitado com um tipo não complexo (isto é, pode ser serializado).
row1
-1
public static class JsonSerializer
{
    public static string Serialize<T>(this T data)
    {
        try
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, data);
            string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
            stream.Close();
            return jsonData;
        }
        catch
        {
            return "";
        }
    }
    public static T Deserialize<T>(this string jsonData)
    {
        try
        {
            DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
            T data = (T)slzr.ReadObject(stream);
            stream.Close();
            return data;
        }
        catch
        {
            return default(T);
        }
    }
}
harryovers
fonte
Isso não serializar tipos anônimos como pela questão
Mark Sowul