Como converter um objeto JSON em um objeto C # personalizado?

247

Existe uma maneira fácil de preencher o meu objeto C # com o objeto JSON passado via AJAX?

Este é o objeto JSON passado para o C # WEBMETHOD a partir da página usando JSON.stringify

{
    "user": {
        "name": "asdf",
        "teamname": "b",
        "email": "c",
        "players": ["1", "2"]
    }
}

C # WebMetod que recebe o objeto JSON

[WebMethod]
public static void SaveTeam(Object user)
{

}

Classe C # que representa a estrutura do objeto JSON passada para o WebMethod

public class User
{
    public string name { get; set; }
    public string teamname { get; set; }
    public string email { get; set; }
    public Array players { get; set; }
}
MHop
fonte
69
Gostaria de acrescentar que você pode usar o json2csharp.com para gerar suas classes de c # para você. Divulgação completa: criei este site.
JonathanK
Verifique este stackoverflow.com/questions/22191167/…
Pratik Bhoir
@JonathanK Você é meu salvador!
Matheno

Respostas:

218

Uma boa maneira de usar JSON em C # é com JSON.NET

Início rápido e documentação da API da do JSON.NET - Site oficial para ajudá-lo a trabalhar com ele.

Um exemplo de como usá-lo:

public class User
{
    public User(string json)
    {
        JObject jObject = JObject.Parse(json);
        JToken jUser = jObject["user"];
        name = (string) jUser["name"];
        teamname = (string) jUser["teamname"];
        email = (string) jUser["email"];
        players = jUser["players"].ToArray();
    }

    public string name { get; set; }
    public string teamname { get; set; }
    public string email { get; set; }
    public Array players { get; set; }
}

// Use
private void Run()
{
    string json = @"{""user"":{""name"":""asdf"",""teamname"":""b"",""email"":""c"",""players"":[""1"",""2""]}}";
    User user = new User(json);

    Console.WriteLine("Name : " + user.name);
    Console.WriteLine("Teamname : " + user.teamname);
    Console.WriteLine("Email : " + user.email);
    Console.WriteLine("Players:");

    foreach (var player in user.players)
        Console.WriteLine(player);
 }
AndreyAkinshin
fonte
5
Isso funciona como um campeão, mas e se eu tiver vários itens no meu json e quiser fazer uma lista de objetos?
Djeroen
@ Djeroen: vejo duas maneiras para isso. Se os itens não estiverem agrupados, tente encontrar uma maneira de dividir a sequência e repita o processo em um loop. Se eles são agrupados fazer um objeto de objetos
user1011138
1
Eu prefiro os forros mencionados em outras respostas .. IMHO.
RayLoveless
Sim, esta não é uma boa abordagem, a seguir utilizando DeserializeObject é muito mais limpo
Andrew
207

Uma vez que todos nós amamos um código de liners

Newtonsoft é mais rápido que o serializador de scripts java. ... este depende do pacote Newtonsoft NuGet, que é popular e melhor que o serializador padrão.

se tivermos classe, use abaixo.

Mycustomclassname oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<Mycustomclassname>(jsonString);

nenhuma classe então use dinâmico

var oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonString);
MSTdev
fonte
95

Para manter suas opções abertas, se você estiver usando o .NET 3.5 ou posterior, aqui está um exemplo finalizado que você pode usar diretamente da estrutura usando Genéricos. Como outros já mencionaram, se não são apenas objetos simples, você realmente deve usar o JSON.net.

public static string Serialize<T>(T obj)
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    MemoryStream ms = new MemoryStream();
    serializer.WriteObject(ms, obj);
    string retVal = Encoding.UTF8.GetString(ms.ToArray());
    return retVal;
}

public static T Deserialize<T>(string json)
{
    T obj = Activator.CreateInstance<T>();
    MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    obj = (T)serializer.ReadObject(ms);
    ms.Close();
    return obj;
}

Você precisará:

using System.Runtime.Serialization;

using System.Runtime.Serialization.Json;
Jammin
fonte
@ChristianPayne ha! Bom ponto, sim, estes devem ser embrulhados. Em retrospectiva olhando para isso, basta usar o JSON.NET!
21713 Jammin
2
Se a classe DataContractJsonSerializer não estiver visível, adicione uma referência ao System.Runtime.Serialization clicando com o botão direito do mouse em References na solução, selecione a guia .NET e selecione System.Runtime.Serialization
DanKodi
1
Um cenário em que este quebra. Se o seu objeto JSON representar propriedades com aspas simples, essa função falhará. por exemplo, não foi possível analisar {'Assunto': 'Enviar por e-mail: Log11 de Atividade do Usuário da Web', 'EmbedAsImage': true}, mas foi capaz de analisar {"Assunto": "Enviar por e-mail: Log de Atividade do Usuário da Web11", "EmbedAsImage" : true}
dreamerkumar
Além disso, eu precisava decorar minha classe simples com os atributos DataContract e DataMember. Não será analisado sem ele.
dreamerkumar
Ao contrário do Vishal, uma classe POCO funcionou perfeitamente para mim ... +1, pois evita uma dependência do JSON.NET.
Dunc 12/12
54

Dado seu exemplo de código, você não precisa fazer mais nada.

Se você passar essa cadeia JSON para o seu método da web, ela analisará automaticamente a cadeia JSON e criará um objeto User preenchido como o parâmetro para o seu método SaveTeam.

Geralmente, porém, você pode usar a JavascriptSerializerclasse como abaixo, ou para obter mais flexibilidade, use qualquer uma das várias estruturas Json existentes (o Jayrock JSON é bom) para facilitar a manipulação do JSON.

 JavaScriptSerializer jss= new JavaScriptSerializer();
 User user = jss.Deserialize<User>(jsonResponse); 
womp
fonte
1
Eu acho que você deve usar um tipo ienumerable (por isso, neste exemplo, List <User>)
Dragouf
Como podemos anular a serialização se ele contém sub modelo de exibição
SrinivasNaidu
1
Para aqueles que procuram, é necessário fazer referência à System.Web.Extensionsmontagem e adicionar a using System.Web.Script.Serializationpara chegar ao JavaScriptSerializer, mas, quando o fizer, essa parece ser a maneira mais limpa de desserializar suas jsonseqüências de caracteres em classes concretas do c #.
Serj Sagan
41

Outra solução realmente simples é usar a biblioteca Newtonsoft.Json:

User user = JsonConvert.DeserializeObject<User>(jsonString);
Daniel
fonte
mas se o objeto User tiver outros dados JSon na propriedade, isso falhará ...
gumuruh
@ gumuruh Acho que não entendi sua declaração. Se você tiver um objeto complexo, as propriedades dos outros objetos complexos serão também convertidas, desde que sua Json String tenha os dados corretamente.
Daniel
33

Os 2 exemplos a seguir fazem uso de qualquer

  1. JavaScriptSerializer em System.Web.Script.Serialization Ou
  2. Json.Decode em System.Web.Helpers

Exemplo 1: usando System.Web.Script.Serialization

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Script.Serialization;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void Test()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            dynamic jsonObject = serializer.Deserialize<dynamic>(json);

            dynamic x = jsonObject["user"]; // result is Dictionary<string,object> user with fields name, teamname, email and players with their values
            x = jsonObject["user"]["name"]; // result is asdf
            x = jsonObject["user"]["players"]; // result is object[] players with its values
        }
    }
}

Uso: objeto JSON para objeto C # personalizado

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Script.Serialization;
using System.Linq;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJavaScriptSerializer()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            User user = new User(json);
            Console.WriteLine("Name : " + user.name);
            Console.WriteLine("Teamname : " + user.teamname);
            Console.WriteLine("Email : " + user.email);
            Console.WriteLine("Players:");
            foreach (var player in user.players)
                Console.WriteLine(player);
        }
    }

    public class User {
        public User(string json) {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            var jsonObject = serializer.Deserialize<dynamic>(json);
            name = (string)jsonObject["user"]["name"];
            teamname = (string)jsonObject["user"]["teamname"];
            email = (string)jsonObject["user"]["email"];
            players = jsonObject["user"]["players"];
        }

        public string name { get; set; }
        public string teamname { get; set; }
        public string email { get; set; }
        public Array players { get; set; }
    }
}

Exemplo 2: usando System.Web.Helpers

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Helpers;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJsonDecode()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            dynamic jsonObject = Json.Decode(json);

            dynamic x = jsonObject.user; // result is dynamic json object user with fields name, teamname, email and players with their values
            x = jsonObject.user.name; // result is asdf
            x = jsonObject.user.players; // result is dynamic json array players with its values
        }
    }
}

Uso: objeto JSON para objeto C # personalizado

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Helpers;
using System.Linq;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJsonDecode()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            User user = new User(json);
            Console.WriteLine("Name : " + user.name);
            Console.WriteLine("Teamname : " + user.teamname);
            Console.WriteLine("Email : " + user.email);
            Console.WriteLine("Players:");
            foreach (var player in user.players)
                Console.WriteLine(player);
        }
    }

    public class User {
        public User(string json) {
            var jsonObject = Json.Decode(json);
            name = (string)jsonObject.user.name;
            teamname = (string)jsonObject.user.teamname;
            email = (string)jsonObject.user.email;
            players = (DynamicJsonArray) jsonObject.user.players;
        }

        public string name { get; set; }
        public string teamname { get; set; }
        public string email { get; set; }
        public Array players { get; set; }
    }
}

Esse código requer a adição do namespace System.Web.Helpers encontrado em,

% ProgramFiles% \ Páginas da Web do Microsoft ASP.NET \ ASP.NET {VERSÃO} \ Assemblies \ System.Web.Helpers.dll

Ou

% ProgramFiles (x86)% \ Páginas da Web do Microsoft ASP.NET \ ASP.NET {VERSÃO} \ Assemblies \ System.Web.Helpers.dll

Espero que isto ajude!


fonte
Essa é uma resposta muito boa, mas o mais complicado é que, com dynamictipos, você não recebe nenhuma verificação de tipo verdadeira. Por exemplo, se o seu JSON contiver "Name" : "Ahmed"e você digitar incorretamente "Nome" no seu código C #, será um erro de tempo de execução (bleh).
Jess
Obrigado! Atualize a resposta para indicar que, para o Exemplo 1, é necessário referenciar System.Web.Extensions.dll
Valamas
1
excelente resposta, a digitação dinâmica também funciona com o json.net v6.0.6!
stackuser83
7
public static class Utilities
{
    public static T Deserialize<T>(string jsonString)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
        {    
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            return (T)serializer.ReadObject(ms);
        }
    }
}

Mais informações, acesse o link a seguir http://ishareidea.blogspot.in/2012/05/json-conversion.html

Sobre DataContractJsonSerializer Classvocê pode ler aqui .

Syam Developer
fonte
5

O uso de JavaScriptSerializer () é menos rigoroso do que a solução genérica oferecida: public static T Deserialize (string json)

Isso pode ser útil ao passar o json para o servidor que não corresponde exatamente à definição de objeto na qual você está tentando converter.

Ioannis Suarez
fonte
1

JSON.Net é sua melhor aposta, mas, dependendo da forma dos objetos e se existem dependências circulares, você pode usar JavaScriptSerializer ou DataContractSerializer.

Sky Sanders
fonte
1

Serializador de JavaScript: requer using System.Web.Script.Serialization;

public class JavaScriptSerializerDeSerializer<T>
{
    private readonly JavaScriptSerializer serializer;

    public JavaScriptSerializerDeSerializer()
    {
        this.serializer = new JavaScriptSerializer();
    }

    public string Serialize(T t)
    {
        return this.serializer.Serialize(t);
    }

    public T Deseralize(string stringObject)
    {
        return this.serializer.Deserialize<T>(stringObject);
    }
}

Serializador de contrato de dados: requer using System.Runtime.Serialization.Json; - O tipo genérico T deve ser serializado mais no contrato de dados

public class JsonSerializerDeserializer<T> where T : class
{
    private readonly DataContractJsonSerializer jsonSerializer;

    public JsonSerializerDeserializer()
    {
        this.jsonSerializer = new DataContractJsonSerializer(typeof(T));
    }

    public string Serialize(T t)
    {
        using (var memoryStream = new MemoryStream())
        {
            this.jsonSerializer.WriteObject(memoryStream, t);
            memoryStream.Position = 0;
            using (var sr = new StreamReader(memoryStream))
            {
                return sr.ReadToEnd();
            }
        }
    }

    public T Deserialize(string objectString)
    {
        using (var ms = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes((objectString))))
        {
            return (T)this.jsonSerializer.ReadObject(ms);
        }
    }
}
BTE
fonte
0

Em vez de enviar apenas como um objeto.

Crie uma classe pública de propriedades acessíveis e envie os dados para o Webmethod.

[WebMethod]
public static void SaveTeam(useSomeClassHere user)
{
}

use os mesmos nomes de parâmetros na chamada ajax para enviar dados.

Praveen Kumar Rejeti
fonte