Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a JToken (or string) to a given Type

TL;DR Version

I have a object of type JToken (but can also be a string) and I need to convert it into a Type contained in the type variable:

Type type = typeof(DateTime); /* can be any other Type like string, ulong etc */ var obj = jsonObject["date_joined"]; /* contains 2012-08-13T06:01:23Z+05:00 */ var result = Some_Way_To_Convert(type, obj); 

The above result should be a DateTime object with the value given in date_joined.

Full Story

I'm using both RestSharp and Json.NET in a Windows Phone project and I'm stuck while trying to deserialize JSON responses from a REST API.

What I'm actually trying to accomplish is to write a generic method that can easily map my JSON response into my CLR entities, much like you can do with RestSharp already. The only problem is that the default RestSharp implementation isn't working for me and it fails to successfully parse the JSON since the response doesn't always return all the properties (I don't return fields which are null from the REST server).

That's why I decided to use Newtonsoft's Json.NET since it has a much more powerful Json deserializing engine. Unfortunately, it doesn't support fuzzy property/field names like RestSharp (or I haven't found any), so it also doesn't map correctly to my CLR entities when I use something like say JsonConvert.DeserializeObject<User>(response.Content).

Here's what my Json looks like (an example actually):

{     "id" : 77239923,     "username" : "UzEE",     "email" : "[email protected]",     "name" : "Uzair Sajid",     "twitter_screen_name" : "UzEE",     "join_date" : "2012-08-13T05:30:23Z05+00",     "timezone" : 5.5,     "access_token" : {         "token" : "nkjanIUI8983nkSj)*#)(kjb@K",         "scope" : [ "read", "write", "bake pies" ],         "expires" : 57723     },     "friends" : [{         "id" : 2347484",         "name" : "Bruce Wayne"     },     {         "id" : 996236,         "name" : "Clark Kent"     }] } 

And here's an example of my CLR entities:

class AccessToken  {     public string Token { get; set; }     public int Expires { get; set; }     public string[] Scope { get; set; }     public string Secret { get; set; } /* may not always be returned */ }  class User {     public ulong Id { get; set; }     public string UserName { get; set; }     public string Email { get; set; }     public string Name { get; set; }     public string TwitterScreenName { get; set; }     public DateTime JoinDate { get; set; }     public float Timezone { get; set; }     public bool IsOnline { get; set; } /* another field that might be blank e.g. */      public AccessToken AccessToken { get; set; }      public List<User> Friends { get; set; } } 

What I want is a simple way to parse the above JSON into the given CLR objects. I've looked around the RestSharp source code and have seen the JsonDeserializer code and I've been able to write a generic extension method DeserializeResponse<T> on JObject that should return a an object of type T. The intended use is something like this:

var user = JObject.Parse(response.Content).DeserializeResponse<User>(); 

The above method should parse the given Json Response to a User entity object. Here's an actual code snippet of what I'm doing in the DeserializeResponse<User> extension method (its based on RestSharp code):

public static T DeserializeResponse<T>(this JObject obj) where T : new() {     T result = new T();     var props = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();     var objectDictionary = obj as IDictionary<string, JToken>;      foreach (var prop in props)     {         var name = prop.Name.GetNameVariants(CultureInfo.CurrentCulture).FirstOrDefault(n => objectDictionary.ContainsKey(n));         var value = name != null ? obj[name] : null;          if (value == null) continue;          var type = prop.PropertyType;          if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))         {             type = type.GetGenericArguments()[0];         }          // This is a problem. I need a way to convert JToken value into an object of Type type         prop.SetValue(result, ConvertValue(type, value), null);      }      return result; } 

I'm guessing that the conversion should be a really straightforward thing to do since its a trivial task. But I've been searching for a quite a while now and still haven't found a way to do it via Json.NET (and lets be honest, the documentation is kinda though to understand and lacks some examples).

Any help would really be appreciated.

like image 660
Uzair Sajid Avatar asked Aug 13 '12 01:08

Uzair Sajid


People also ask

What is JToken?

JToken is the abstract base class of JObject , JArray , JProperty , and JValue , which represent pieces of JSON data after they have been parsed. JsonToken is an enum that is used by JsonReader and JsonWriter to indicate which type of token is being read or written.

What is the difference between JToken and JObject?

JToken is the base class for all JSON elements. You should just use the Parse method for the type of element you expect to have in the string. If you don't know what it is, use JToken, and then you'll be able to down cast it to JObject, JArray, etc. In this case you always expect a JObject, so use that.

Is JToken a JArray?

As stated by dbc, a JToken that represent a JArray, is already a JArray. That is if the JToken. Type equals an JTokenType.

What is JObject parse in C#?

JObject class has parse method; it parses the JSON string and converts it into a Key-value dictionary object. In the following example, I have used “JObject. Parse” method and retrieved data using key. string jsonData = @"{ 'FirstName':'Jignesh', 'LastName':'Trivedi' }"; var details = JObject.


1 Answers

There is a ToObject method now.

var obj = jsonObject["date_joined"]; var result = obj.ToObject<DateTime>(); 

It also works with any complex type, and obey to JsonPropertyAttribute rules

var result = obj.ToObject<MyClass>();  public class MyClass  {      [JsonProperty("date_field")]     public DateTime MyDate {get;set;} } 
like image 58
Softlion Avatar answered Oct 05 '22 21:10

Softlion