.NET Json Serialization Exception for C# - c#

I'm using JSON.net in C# for an Excel VSTO Add in and pulling in JSON via web service.
I have verified the JSON I pull is valid (online JSON Validator) but am unable to convert the JSON into Objects in C# to use.
When I run the code below I get the exception below.
Any ideas on who I can covert the JSON correctly?
Exception:
Newtonsoft.Json.JsonSerializationException:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'Bliss.Ribbon1+RootObject[]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type
(e.g. not a primitive type like integer, not a collection type like an array or List<T>)
that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Code:
public async Task<string> getline()
{
<--- Set Client, Execute Request --->
//JSON content shown below
string content = await response.Content.ReadAsStringAsync();
RootObject[] dims = JsonConvert.DeserializeObject<RootObject[]>(content);
return content;
}
public class RootObject
{
public List<string> ledger { get; set; }
public List<string> ledgerAlias { get; set; }
public List<string> entity { get; set; }
public List<string> entityAlias { get; set; }
public List<string> scenario { get; set; }
public List<string> period { get; set; }
public List<string> location { get; set; }
public List<string> measures { get; set; }
}
JSON:
{
"acc":["A","B"],
"accAlias":["ACE","BCE"],
"company":["PEP", "KO"],
"companyAlias":["Pepsi", "Coco-Cola"],
"scenario":["Sales", "Expenses"],
"year": ["2016","2017"],
"areaCode":["123","131","412"],
"clients":["32340-0120","3031-0211","3412-0142"]
}

The JSON represents a single instance of the object, not an array. So instead of this:
RootObject[] dims = JsonConvert.DeserializeObject<RootObject[]>(content)
use this:
RootObject dims = JsonConvert.DeserializeObject<RootObject>(content)
Conversely, if it should be an array, make the JSON itself an array (containing a single element) by surrounding it with brackets:
[{
"acc":["A","B"],
"accAlias":["ACE","BCE"],
"company":["PEP", "KO"],
"companyAlias":["Pepsi", "Coco-Cola"],
"scenario":["Sales", "Expenses"],
"year": ["2016","2017"],
"areaCode":["123","131","412"],
"clients":["32340-0120","3031-0211","3412-0142"]
}]
Edit: As others have also been pointing out, the properties on the JSON object don't actually match that class definition. So while it may "successfully" deserialize, in doing so it's going to ignore the JSON properties it doesn't care about and initialize to default values the class properties.
Perhaps you meant to use a different class? Or different JSON? Or rename one or more properties in one or the other?
Either way, the difference between a single instance and an array of instances is the immediate problem. But in correcting that problem you're going to move on to this next one.

The RootObject and the json are not compatible. You could deserialize using a dictionary. Try this:
var dims = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(content);

Related

I am trying to deserialize a JSON into a list of objects using .NET 3.1

I have the following Json:
{
"Id":"2727",
"Region":"US",
"Data":[
{
"Title":"Director",
"JobDescription":"Coordinates the department activity",
"Department":"HR"
},
{
"Title":"Programmer",
"JobDescription":"Enterprise software developer",
"Department":"FR"
}
]
}
My format looks like this:
public class Data
{
public string Title { get; set; }
public string JobDescription { get; set; }
public string Department { get; set; }
}
public class Format
{
public string Id { get; set; }
public string Region { get; set; }
public List<Data> Data {get; set;}
}
I have tried to deserialize it like this:
var objects = JsonConvert.DeserializeObject<IEnumerable<Format>>(File.ReadAllText("mockJson.json")).ToList();
I am getting this exception:
An unhandled exception of type
'Newtonsoft.Json.JsonSerializationException' occurred in
Newtonsoft.Json.dll Cannot deserialize the current JSON object (e.g.
{"name":"value"}) into type
'System.Collections.Generic.IEnumerable`1[JSONParsingExample.Format]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path 'GlobalOrgId', line 2,
position 15.
Just posting this as an answer because I think its worth making it more visible. I assumed the method call was going to have some issues with nesting lists inside a json, but I'm pleased to see it works.
Format format = JsonConvert.DeserializeObject<Format>(File.ReadAllText("mockJson.json"));
I inspected the elements and they all seem to be where they are supposed to be.
Just be careful because JsonConvert.DeserializeObject<T> returns an object of type T, not IEnumerable<T>.
When working with JSON in .NET I'd recommend moving over to the new built in stuff.
https://devblogs.microsoft.com/dotnet/net-core-image-processing/

c# Deserialize unlabelled JSON array

I am attempting to deserialize a piece of JSON with a specific structure like so:
{
"label1": "value1",
"label2": [
[
[
"concept_id_1",
"concept_1"
],
score_1
],
[
[
"concept_id_2",
"concept_2"
],
score_2
],
……
],
"label3": "value3",
"label4": "value4"
}
For what it's worth, the scores are floats and everything else is a string. The number of returned concepts under "label2" is variable.
I'm attempting to deserialize it using JSON.net. The only content I actually care about is the inside nest of arrays labelled "label2", however the lack of labels inside the arrays is blocking me at every turn.
I've tried a variety of approaches, but the most successful so far seems to be this:
public class Parsed_JSON {
public string label1 { get; set; }
public ICollection<Full_Result> label2 { get; set; }
public string label3 { get; set; }
public string label4 { get; set; }
}
public class Full_Result {
public IList<string> values { get; set; }
public float score { get; set; }
}
Parsed_JSON result = JsonConvert.DeserializeObject<Parsed_JSON>(JSON);
However this is failing with the error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'JSON_Parsing+Full_Result' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Ultimately I'll be looking to iterate through the contents of label2 so that I can build a DataTable of them like so:
concept_id_1 concept_1 score_1
concept_id_2 concept_2 score_2
How can I deserialize this JSON?
You can use the custom JsonConverter ObjectToArrayConverter<Full_Result> from this answer to C# JSON.NET - Deserialize response that uses an unusual data structure to deserialize your JSON into your existing typed data model. Modify Full_Result as follows:
[JsonConverter(typeof(ObjectToArrayConverter<Full_Result>))]
public class Full_Result
{
[JsonProperty(Order = 1)]
public IList<string> values { get; set; }
[JsonProperty(Order = 2)]
public float score { get; set; }
}
And you will now be able to deserialize as follows:
Parsed_JSON result = JsonConvert.DeserializeObject<Parsed_JSON>(JSON);
Notes:
ObjectToArrayConverter<T> works by mapping the serializable members of T to an array, where the array sequence is defined by the value of the JsonPropertyAttribute.Order attribute applied to each member. Data contract attributes with DataMemberAttribute.Order set could be used instead, if you prefer.
In your JSON the "score" values are not actually numbers:
score_1
score_2
I am assuming that this is a typo in the question and that these values are in fact well-formed numbers as defined by the JSON standard.
Sample fiddle here.

Newsoft Json deserialize into products Collection not working

I am creating a windows phone silver light 8 app.
I have a Json string and I am trying to convert it into a List of objects and each object is a object of a class classed "Product" and list is supposed to be products. ultimately I want it to convert into Observable collection so that I can bind that collection to my listbox in my windows Silverlight phone app.
Here is my class
public class Product
{
public string _id { get; set; }
public string code { get; set; }
public string name { get; set; }
public string imgAddress { get; set; }
public int queryCount { get; set; }
}
Here is code to deserialize the json
var PDS = "{\"products\":[{\"_id\":\"58b2\",\"code\":\"59034\",\"name\":\"somename1\",\"imgAddress\":\"https://someimageurl/.../.jpg\",\"queryCount\":0},{\"_id\":\"58b3\",\"code\":\"59035\",\"name\":\"somename2\",\"imgAddress\":\"https://someimageurl2/.../.jpg\",\"queryCount\":1}]}";
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
Here is my collection for binding
public ObservableCollection<Product> Products { get; set; }
ERRORS
>> First I was getting parsing error so I escaped all quotes within the string like this \"
**>>**But then it was only converting to a normal string like object but I want to convert to a collection of products of type "Product"
>> Exception
Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[PivotApp1.Product]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'products', line 1, position 12.
Thanks in advance
You can deserialize it this way (but you'll have somehow to reformat your JSON string):
from
var PDS = "{"products":[{"_id":"58b2","code":"59034","name":"somename1","imgAddress":"https://someimageurl/.../.jpg","queryCount":0},{"_id":"58b3","code":"59035","name":"somename2","imgAddress":"https://someimageurl2/.../.jpg","queryCount":1}]}";
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
to
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
Then
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
More infos --> Deserialize a collection
No need of creating another class as suggested!
EDIT:
Actually you get this exception because your JSON string represents an object 'products' containing a list of 'Product' and this doesn't directly relate to your root class.
This is what your current JSON look like:
Your JSON string result should be something like that instead:
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
Represented as following (notice the slight difference):
Using this JSON string, it will work with no exception raised:
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
Or, if you can't change the resulting JSON string in PDS, you can do what J. Tuc suggested (via a new "RootClass").
your JSON string had to be changed to get the code to compile:
var PDS = "{'products':[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]}";
You need another object with a collection of Product as a property called products in order to deserialize your JSON
This may not be the best solution but it works:
Create another class:
public class RootObject
{
public List<Product> products;
}
use this code to deserialize your JSON:
var pds = JsonConvert.DeserializeObject(PDS, typeof(RootObject));
if you are in control of your JSON string you might consider changing it to this (removing 'products' property and ending up with just an array of products in the JSON string):
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
Then you might be able to use the solution proposed by TaiT's (deserializing directly to a List of Product) :
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);

Converting json to objects in C#

I have data in the following format. I want to convert this data to objects.
Result = {
"Location": [
"bangalore",
1,
"chennai",
1,
"mumbai",
1,
"delhi",
0,
"Agra",
0
]
}
In my Location.cs i have the following fields. i want to assign the data to this fields. How can i achieve this
public string loc { get; set; }
public int count { get; set; }
I tried with
Location = Result.ToObject<List<Location>>();
but not working getting the following error
{"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[Location]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'Location'."}
Take a look at the native json deserializaton that is part of .NET
MSDN - How to: Serialize and Deserialize JSON Data
The problem is this: Result is a JSON object, not a JSON array, therefore you can't convert it to a List<Location>.
You would need a class that contains a list of locations and convert to that class:
public class LocationsContainer
{
public List<Location> Location { get; set; }
}
Result.ToObject<LocationsContainer>();
Try with Json.NET library.
List<Location> locations = JsonConvert.DeserializeObject<List<Location>>(result);

JSON object deserialize to c# object - OpenTSDB

I am dealing with JSON for the first time and getting data from OpenTSDB. I've created a c# class to deserialize the JSON to but I am getting the error 'Cannot deserialize the current JSON array' as described below.
My c# code to get JSON:
var request = WebRequest.Create("http://localhost:4242/api/query?start=2013/08/21-12:00:00&end=2013/08/22-12:00:00&m=sum:tcollector.collector.lines_sent&o=&yrange=%5B0:%5D&wxh=924x773");
request.ContentType = "application/json; charset=utf-8";
string text;
try
{
var response = (HttpWebResponse) request.GetResponse();
using (var sr = new StreamReader(response.GetResponseStream()))
{
text = sr.ReadToEnd();
}
uxResponse.Text = text;
OpenTSDBResponse myObject = (OpenTSDBResponse)Newtonsoft.Json.JsonConvert.DeserializeObject(text, typeof(OpenTSDBResponse));
var variable = Newtonsoft.Json.JsonConvert.DeserializeObject(text);
//var tester = myObject;
}
catch (Exception ex)
{
uxResponse.Text = GetFullExceptionMessage(ex);
}
The JSON I am receiving from the above code (i.e. the 'text' variable):
[{
"metric":"tcollector.collector.lines_sent",
"tags":
{
"host":"ubuntu1"
},
"aggregateTags":["collector"],
"dps":
{
"1377050434":1271779.0,
"1377050494":1272073.0,
"1377050554":1272502.0,
"1377050614":1273632.0,
"1377050674":1273867.0
}
}]
My c# classes
internal class OpenTSDBResponse
{
[JsonProperty("metric")]
public string Metric { get; set; }
[JsonProperty("tags")]
public Tags Tags { get; set; }
[JsonProperty("aggregateTags")]
public string[] AggregateTags { get; set; }
[JsonProperty("dps")]
public List<TimeValue> TimeValues { get; set; }
}
internal class Tags
{
[JsonProperty("host")]
public string Host { get; set; }
}
internal class TimeValue
{
[JsonProperty("Time")]
public double Time { get; set; }
[JsonProperty("Value")]
public double Value { get; set; }
}
The error when deserializing object:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'MyNamespace.OpenTSDBResponse' because the type requires a JSON
object (e.g. {"name":"value"}) to deserialize correctly.To fix this
error either change the JSON to a JSON object (e.g. {"name":"value"})
or change the deserialized type to an array or a type that implements
a collection interface (e.g. ICollection, IList) like List that can
be deserialized from a JSON array. JsonArrayAttribute can also be
added to the type to force it to deserialize from a JSON array.Path
'', line 1, position 1.
Additional Information
I used the codeproject deserialize JSON project to create my basic classes, but it created a new c# property for each '"1377050434":1271779.0,' so I updated to use my TimeValue class. http://www.codeproject.com/Tips/79435/Deserialize-JSON-with-C
Question:
How do I get this into an appropriate c# class structure?
Additional Information in response to users comments below:
bjaminn's comment:
I believe the JSON you are receiving is an array. The exception is trying to say you are converting an object[] to OpenTSDBResponse when you really want OpenTSDBResponse[]. Another way to debug this would be to look at the variable variable and see what type it is in the debugger. Of course the line that throws the exception would need to be commented out.
Outcome: I modified the deserialize like this
OpenTSDBResponse[] myObject = (OpenTSDBResponse[])Newtonsoft.Json.JsonConvert.DeserializeObject(text, typeof(OpenTSDBResponse[]));
but received the following error when I ran it:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[MyNamespace.OpenTSDBResponseJsonTypes.TimeValue]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path '[0].dps.1377050434', line 1, position 121.
Additional Notes on working solution for other new to JSON
I have added another property to my class for the Dictionary as it's really "unix-time-stamp-data","Value". This allows me to work in c# with datetime/values. There may be a better way for casting but this works an doesn't cause any noticeable performance issues for my scenario.
[JsonProperty("dps")]
public Dictionary<string, double> TimeValues { get; set; }
public List<TimeValue> DataPoints
{
get
{
List<TimeValue> times = new List<TimeValue>();
DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
foreach (var item in TimeValues)
{
times.Add(new TimeValue
{
Time = dtDateTime.AddSeconds(double.Parse(item.Key)).ToLocalTime(),
Value = item.Value
});
}
return times;
}
}
I believe the JSON you are receiving is an array. The exception is trying to say you are converting an object[] to OpenTSDBResponse when you really want OpenTSDBResponse[].
Another way to debug this would be to look at the variable variable and see what type it is in the debugger. Of course the line that throws the exception would need to be commented out.
Tackling new error
It looks like DPS is not a proper JSON array. You could parse it to a dictionary since it looks like the keys will be different in each JSON call.
JSON convert dictionary to a list of key value pairs
New class:
internal class OpenTSDBResponse
{
[JsonProperty("metric")]
public string Metric { get; set; }
[JsonProperty("tags")]
public Tags Tags { get; set; }
[JsonProperty("aggregateTags")]
public string[] AggregateTags { get; set; }
[JsonProperty("dps")]
public Dictionary<string,double> TimeValues { get; set; }
}
You can such so modify your Json Data and your C# Code,for example
[{
"metric":"tcollector.collector.lines_sent",
"tags":
{
"host":"ubuntu1"
},
"aggregateTags":["collector"],
"dps":
[
{"Time":"1377050434","Value":1271779.0},
{"Time":"1377050554","Value":1272502.0}
]
}]
c# Code:
You provide the data is an Array,so when you deserialize the string,you must such so use generic format of deserializeobject
object obj=Newtonsoft.Json.JsonConvert.DeserializeObject<List<OpenTSDBResponse>>(json.ToString());

Categories

Resources