JObject.Parse vs JsonConvert.DeserializeObject
The LINQ-to-JSON API (JObject
, JToken
, etc.) exists to allow working with JSON without needing to know its structure ahead of time. You can deserialize any arbitrary JSON using JToken.Parse
, then examine and manipulate its contents using other JToken
methods. LINQ-to-JSON also works well if you just need one or two values from the JSON (such as the name of a county).
JsonConvert.DeserializeObject
, on the other hand, is mainly intended to be used when you DO know the structure of the JSON ahead of time and you want to deserialize into strongly typed classes. For example, here's how you would get the full set of county data from your JSON into a list of County
objects.
class Program
{
static void Main(string[] args)
{
string countiesJson = "{'Everything':[{'county_name':null,'description':null,'feat_class':'Civil','feature_id':'36865',"
+"'fips_class':'H1','fips_county_cd':'1','full_county_name':null,'link_title':null,'url':'http://www.alachuacounty.us/','name':'Alachua County'"+ ",'primary_latitude':'29.7','primary_longitude':'-82.33','state_abbreviation':'FL','state_name':'Florida'},"+
"{'county_name':null,'description':null,"+ "'feat_class':'Civil','feature_id':'36866','fips_class':'H1','fips_county_cd':'3','full_county_name':null,'link_title':null,'url':'http://www.bakercountyfl.org/','name':'Baker County','primary_latitude':'30.33','primary_longitude':'-82.29','state_abbreviation':'FL','state_name':'Florida'}]}";
foreach (County c in JsonParseCounties(countiesJson))
{
Console.WriteLine(string.Format("{0}, {1} ({2},{3})", c.name,
c.state_abbreviation, c.primary_latitude, c.primary_longitude));
}
}
public static List<County> JsonParseCounties(string jsonText)
{
return JsonConvert.DeserializeObject<RootObject>(jsonText).Counties;
}
}
public class RootObject
{
[JsonProperty("Everything")]
public List<County> Counties { get; set; }
}
public class County
{
public string county_name { get; set; }
public string description { get; set; }
public string feat_class { get; set; }
public string feature_id { get; set; }
public string fips_class { get; set; }
public string fips_county_cd { get; set; }
public string full_county_name { get; set; }
public string link_title { get; set; }
public string url { get; set; }
public string name { get; set; }
public string primary_latitude { get; set; }
public string primary_longitude { get; set; }
public string state_abbreviation { get; set; }
public string state_name { get; set; }
}
Notice that Json.Net uses the type argument given to the JsonConvert.DeserializeObject
method to determine what type of object to create.
Of course, if you don't specify a type when you call DeserializeObject
, or you use object
or dynamic
, then Json.Net has no choice but to deserialize into a JObject
. (You can see for yourself that your dynamic variable actually holds a JObject
by checking jResults.GetType().FullName
.) So in that case, there's not much difference between JsonConvert.DeserializeObject
and JToken.Parse
; either will give you the same result.
JSon.Net JObject.FromObject Vs JsonConvert.DeserializeObjectJObject(JsonConvert.SerializeObject(obj));
This is faster:
JObject.FromObject(obj);
It builds a JObject directly from the object. The other method serializes the object to JSON a JSON string and then parses the JSON to build a JObject.
Documentation: JObject.FromObject
JObject Not Parsing Values I need
- Take
json["links"]
asJArray
. - Use Linq to retrieve
url
from the element in (1) and cast it tostring
.
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
JObject json = JObject.Parse(contents);
JArray array = json["links"] as JArray;
List<string> links = array.Select(x => (string)x["url"]).ToList();
Sample demo on .NET Fiddle
How to deserialize a JObject to .NET object
According to this post, it's much better now:
// pick out one album
JObject jalbum = albums[0] as JObject;
// Copy to a static Album instance
Album album = jalbum.ToObject<Album>();
Documentation: Convert JSON to a Type
Newtonsoft JSON Deserialize Dynamically
Have you looked into using JsonLinq and JObject.Parse()
? You can then using something like the following:
string Data = "{\"t\":\"1339886\",\"a\":true,\"data\":[],\"Type\":[['Ants','Biz','Tro']]}";
JObject J = JObject.Parse(Data);
string[] Types = J["Type"][0].ToObject<string[]>();
Note: I didn't test this against your data structure.
Deserialize a class to a dictionary in c# using JsonConvert.DeserializeObject or JObject.Parse
Finally I could resolve the issue:
For the first problem as suggested by @Camilo I created a wrapper.
For the second I created a custom JsonConverter which made the job for me like below.
internal class TranslationsToDictionaryObjectConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(List<CountryInfoModel>).IsAssignableFrom(objectType)
|| typeof(List<CurrencyInfoModel>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
Dictionary<string, string> dict = new Dictionary<string, string>();
try
{
foreach (var item in token)
{
dict.Add(item["languageCode"].ToString(), item["translatedName"].ToString());
}
}
catch
{
// ignored
}
return dict;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
}
After that the model would look like:
[Serializable]
public class CountryInfoModel
{
public int BwinId { get; set; }
public string TranslatedName { get; set; }
public string TwoLetterCode { get; set; }
public bool LoginAllowed { get; set; }
public bool RegistrationAllowed { get; set; }
[JsonConverter(typeof(TranslationsToDictionaryObjectConverter))]
public Dictionary<string, string> Translations { get; set; }
}
Why isn't JObject converting the JSON string?
You are getting an error because "\"User sent null or empty data\""
is not a JSON object, so it cannot be parsed by JObject.Parse
. Instead you should use JToken.Parse
. This method can handle any kind of JSON -- objects, arrays and simple values. The IsValid
extension method is defined to work on JToken
, so it should still work fine with this change.
As an aside, when the JToken
validates successfully, you don't need to deserialize the JSON a second time with JsonConvert.DeserializeObject<T>()
. You can convert the token to your object directly using JToken.ToObject<T>()
instead.
So in other words, change this code:
var jObject = JObject.Parse(json);
return jObject.IsValid(parsedSchema) ? JsonConvert.DeserializeObject<T>(json) : default(T);
To this:
var jToken = JToken.Parse(json);
return jToken.IsValid(parsedSchema) ? jToken.ToObject<T>() : default(T);
To be extra safe you could put a try/catch block around the parsing. That way if you get a string that isn't even JSON at all, you can handle that as well. So then you would have:
internal static T TryParseJson<T>(this string json, string schema) where T : new()
{
var parsedSchema = JSchema.Parse(schema);
try
{
var jToken = JToken.Parse(json);
return jToken.IsValid(parsedSchema) ? jToken.ToObject<T>() : default(T);
}
catch (JsonException ex)
{
// optionally log the exception here
return default(T);
}
}
Deserializing and working with a JSON object
First you need to create a class to work with the returned objects (assuming you know what you are getting ahead of time).
public class ShoppingbasketItem
{
public double price { get; set; }
public string product { get; set; }
public int quantity { get; set; }
public int total { get; set; }
}
public class Shoppingbasket
{
public List<ShoppingbasketItem> shoppingbasket { get; set; }
}
Then you can deserialize the objects into your C# code and then do whatever you would need to with them from there.
var products = Newtonsoft.Json.JsonConvert.DeserializeObject<Shoppingbasket>(Request.Cookies.Get("wrkb").Value);
So to compute a sum of the total you could just iterate the list from the basket.
double totalSum = 0.0;
foreach(var item in products.shoppingbasket)
{
totalSum += item.quantity * item.price;
}
Edit
To achieve the grouping you are looking for, you could do something like this. It is probably not the best solution, but off the top of my head it is what I thought of.
var grouped = new Dictionary<string, ShoppingbasketItem>();
foreach (var item in products.shoppingbasket)
{
ShoppingbasketItem temp = null;
if (grouped.TryGetValue(item.product, out temp))
{
temp.quantity += item.quantity;
temp.total += item.total;
}
else
{
grouped[item.product] = item;
}
}
JSON JObject.Parse modifies json string
It does not really modify your string, it just parses your date string into DateTime
object when you call JObject.Parse
. If you do this:
var obj = JObject.Parse(json);
var values = (JArray) obj["valuesList"];
var time = (JValue) values[0]["TimeCaptured"];
Console.WriteLine(time.Value.GetType());
You notice that time.Value
is of type DateTime
. Then you do this:
JsonConvert.DeserializeObject<List<IValuePacket>>(jobject["valuesList"].ToString());
By doing that you convert valueList
back to json, but now TimeCaptured
is DateTime
and not a string, so that DateTime
object is converted to json string using whatever date time format is used by JSON.NET by default.
You can avoid parsing strings that look like dates to .NET DateTime
objects by parsing json to JObject
like this:
JObject obj;
using (var reader = new JsonTextReader(new StringReader(json))) {
// DateParseHandling.None is what you need
reader.DateParseHandling = DateParseHandling.None;
obj = JObject.Load(reader);
}
Then type of TimeCaptured
will be string, as you expect.
Side note: there is no need to convert JToken
back to string and then call JsonConvert.Deserialize
on that string. Instead, do this:
var values = obj["valuesList"].ToObject<List<IValuePacket>>();
Related Topics
Cssrewriteurltransform with or Without Virtual Directory
How to Make My Windows Form App Snap to Screen Edges
How to Convert a Datetime to the Number of Seconds Since 1970
How to Mock Out a .Net Httpwebresponse
C# Release Version Has Still .Pdb File
How to Open a Serial Port by Friendly Name
Wait for File to Be Freed by Process
How to Copy the Contents of a String to the Clipboard in C#
Practical Usage of Virtual Functions in C#
Convert an Enum to Another Type of Enum
How to Tell If My Application Is Running as a 32-Bit or 64-Bit Application
Create a .Txt File If Doesn't Exist, and If It Does Append a New Line
Wpf Error 40 Bindingexpression Path Error: Property Not Found on 'Object'
How to Remove Item from Querystring in ASP.NET Using C#
String Format Numbers Thousands 123K, Millions 123M, Billions 123B
Rx: How to Respond Immediately, and Throttle Subsequent Requests