How to convert a JSON response to a C#object?

Asked

Viewed 25,439 times

19

I’m making a request and getting a JSON like this:

{
  "id": "1000000000000000", 
  "name": "BrunoLM", 
  "first_name": "Bruno", 
  "last_name": "X", 
  "link": "http://stackoverflow.com/users/340760/brunolm", 
  "username": "brunolm", 
  "bio": "...",
  "gender": "male", 
  "timezone": -2, 
  "locale": "en_US"
}

But not always the server sends all these fields, sometimes it can come without locale, or link...

I would like to convert this to an object and be able to access by properties:

objeto.name      // ou objeto.Name
objeto.last_name // ou objeto.LastName

How to do this? What is most recommended?

If the most recommended option is to use some library is a question of curiosity: it is possible to do using only what . NET offers?

7 answers

19


I recommend using the Json.NET

Take the example of Documentation

Product product = new Product();

product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string output = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "ExpiryDate": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);
  • 2

    If you don’t have a class to map the Json you can use as dynamic. Example: dynamic deserializado = JsonConvert.DeserializeObject(serializado); and access properties such as deserializado.Name.

7

To do this without using any external library, you can take advantage of the fact that JSON is a subset of Javascript, and use the JavaScriptSerializer from the System.Web.Extensions.dll (.NET 3.5 SP1):

JavaScriptSerializer ser = new JavaScriptSerializer();
Dictionary dict = ser.Deserialize<Dictionary<string,object>>(input);

As the result is a Dictionary, the lack of any field will not harm the result.

According to that answer in the English OS, it is also possible to define a class/set of classes to receive a result - instead of a Dictionary - so that you can access the properties the way you prefer. I just don’t know how he’d behave with fields missing, I’d have to take a test.

Example code of the above question:

using System.Collections.Generic;
using System.Web.Script.Serialization;
public class NameTypePair
{
    public string OBJECT_NAME { get; set; }
    public string OBJECT_TYPE { get; set; }
}
public enum PositionType { none, point }
public class Ref
{
    public int id { get; set; }
}
public class SubObject
{
    public NameTypePair attributes { get; set; }
    public Position position { get; set; }
}
public class Position
{
    public int x { get; set; }
    public int y { get; set; }
}
public class Foo
{
    public Foo() { objects = new List<SubObject>(); }
    public string displayFieldName { get; set; }
    public NameTypePair fieldAliases { get; set; }
    public PositionType positionType { get; set; }
    public Ref reference { get; set; }
    public List<SubObject> objects { get; set; }
}
static class Program
{

    const string json = @"{
  ""displayFieldName"" : ""OBJECT_NAME"", 
  ""fieldAliases"" : {
    ""OBJECT_NAME"" : ""OBJECT_NAME"", 
    ""OBJECT_TYPE"" : ""OBJECT_TYPE""
  }, 
  ""positionType"" : ""point"", 
  ""reference"" : {
    ""id"" : 1111
  }, 
  ""objects"" : [
    {
      ""attributes"" : {
        ""OBJECT_NAME"" : ""test name"", 
        ""OBJECT_TYPE"" : ""test type""
      }, 
      ""position"" : 
      {
        ""x"" : 5, 
        ""y"" : 7
      }
    }
  ]
}";

    static void Main()
    {
        JavaScriptSerializer ser = new JavaScriptSerializer();
        Foo foo = ser.Deserialize<Foo>(json);
    }
}

5

You can use the method Json.Decode (part of ASP.NET MVC) to obtain a dynamic object with JSON properties:

dynamic pessoa = Json.Decode(json);

Console.WriteLine(pessoa.name);

And if you have a class with the same properties as JSON, you can use Json.Decode<T> to obtain an instance of the desired object:

Pessoa pessoa = Json.Decode<Pessoa>(json);

Console.WriteLine(pessoa.name);

5

Fluent URL Http

There is a component called Fluent URL Http very cool to do all this task of performing a request and receive an object already deserialized.

First install the package in your project using the Nuget Package Flurl..

PM> Install-Package Flurl.Http

Then, just consume and make requests in the most elegant way I’ve ever seen:

var result = await "https://api.mysite.com"
    .AppendPathSegment("person") // https://api.mysite.com/person
    .SetQueryParams(new { a = 1, b = 2 }) // https://api.mysite.com/person?a=1&b=2
    .WithOAuthBearerToken("my_oauth_token")
    .PostJsonAsync(new { first_name = "Frank", last_name = "Underwood" }) // { "first_name": "Frank", "last_name": "Underwook" }
    .ReceiveJson<T>();

2

Using Dynamic

It is possible to extend a DynamicObject to obtain the values as follows:

public class DynamicJsonObject : DynamicObject
{
    private IDictionary<string, object> Dictionary { get; set; }

    public DynamicJsonObject(IDictionary<string, object> dictionary)
    {
        this.Dictionary = dictionary;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = this.Dictionary[binder.Name];

        if (result is IDictionary<string, object>)
        {
            result = new DynamicJsonObject(result as IDictionary<string, object>);
        }
        else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
        {
            result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
        }
        else if (result is ArrayList)
        {
            result = new List<object>((result as ArrayList).ToArray());
        }

        // nunca lança exceção se não encontrar o valor
        return true;
        // this.Dictionary.ContainsKey(binder.Name);
    }
}

And extend the JavaScriptConverter to obtain the values

public class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        if (type == typeof(object))
        {
            return new DynamicJsonObject(dictionary);
        }

        return null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(object) })); }
    }
}

And to use

JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });

dynamic json = jss.Deserialize(jsonString, typeof(object));

This way you can dynamically access the values of the object.

json.name
json.id
// ...

Could modify the method TrySetMember of DynamicJsonObject so that the values of the object could be modified. As shown, it only serves as a reading.

2

Datacontractjsonserializer

There is also the DataContractJsonSerializer, that requires the properties of a class to have the attribute [DataMember].

This class can be serialized with the DataContractJsonSerializer, but the property ID will not be included.

[DataContract]
public class TestClass
{
    public int ID { get; set; }

    [DataMember(Name = "número")]
    public int Number { get; set; }
}

This way you can use

var js = new DataContractJsonSerializer(typeof(TestClass));

using (var ms = new MemoryStream())
{
    js.WriteObject(ms, new TestClass { ID = 1, Number = 55 });

    // {"número":55}
    string jsonSerializado = Encoding.UTF8.GetString(ms.ToArray());

    ms.Position = 0;

    // new TestClass { ID = 0, Number = 55 }
    var jsonDeserealizado = (TestClass)js.ReadObject(ms);
}

-3

return Json(new { id= "1000000000000000", name= "BrunoLM", first_name= "Bruno", last_name= "X", link= "http://stackoverflow.com/users/340760/brunolm", username= "brunolm", bio= "...", gender= "male", timezone= -2, locale "en_US" });
  • 1

    Could explain what this code does?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.