Using JSON.net to deserialize a list of nested objects - c#

Thanks in advance for your help.
I have a JSON file that contains a list of nested objects. Using the code below - I get an exception on the call to DeserializeObject. We are using JSON.net
Any help is appreciated
JSON:
[
{
"Email": "james#example.com",
"Active": true,
"CreatedDate": "2013-01-20T00:00:00Z",
"Input": {
"User": "Jim",
"Admin": "John"
},
"Output": {
"Version": "12345",
"Nylon": "None"
}
},
{
"Email": "bob#example.com",
"Active": true,
"CreatedDate": "2013-01-21T00:00:00Z",
"Input": {
"User": "Bob",
"Admin": "John"
},
"Output": {
"Version": "12399",
"Nylon": "134"
}
}
]
To support the deserialization I have created the following class structure.
public class Test002
{
public class Input
{
public string User { get; set; }
public string Admin { get; set; }
}
public class Output
{
public string Version { get; set; }
public string Nylon { get; set; }
}
public class RootObject
{
public string Email { get; set; }
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
public Input input { get; set; }
public Output output { get; set; }
}
public class TestCases
{
public List<RootObject> rootObjects { get; set; }
}
}
And finally here is the call to JSON.net JsonConvert.DeserializeObject - throws the following exception.
Test002.TestCases tTestCases = JsonConvert.DeserializeObject<Test002.TestCases>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));
I think I need something like this - to deseralize the list of objects - The code below fails
Test002.TestCases tTestCases = JsonConvert.DeserializeObject<IList<Test002.TestCases>>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));
Exception:
An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code
Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'APISolution.Test002+TestCases' 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.

Why don't change TestCases to be a list? Works perfectly.
public class TestCases : List<RootObject> {}

The issue here is that you're trying to deserialize into an IList. IList is an interface, not a concrete type so JSON.NET doesn't know what to create. You need to tell it the exact type you want:
List<Test002.TestCases> tTestCases = JsonConvert.DeserializeObject<List<Test002.TestCases>>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));
You could cast that into an IList like this:
IList<Test002.TestCases> tTestCases = JsonConvert.DeserializeObject<List<Test002.TestCases>>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));

Perhaps try something as simple as this:
var tTestCases = JsonConvert.DeserializeObject<Test002.RootObject[]>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));

According to the json-data specified, you got some IEnumerable of RootObjects.
Your classes are well-composed, except the Test002 class. Everything should be OK if you try to deserialize json-data as List. Try something like
var result = JsonConvert.DeserializeObject<List<RootObject>>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"));
If you strongly need the instance of your Test002 class, you should use
Test002.TestCases result = new TestCases(){
rootObjects = JsonConvert.DeserializeObject<List<RootObject>(File.ReadAllText(#"C:\test\Automation\API\Test002.json"))
};

Related

deserialize json into my C# object gives error

I get such JSON and want to deserialize it into my C# object. But this ends up in an error that cannot deserialize. Can I get help in fixing this?
public class UserDto {
public string Id { get; set; }
public string Name { get; set; }
public List<string> Permissions { get; set; }
}
Above is the model object for binding the API output
HttpResponseMessage response = await client.GetAsync($"/users");
if (!response.IsSuccessStatusCode || response.Content == null) {
return null;
}
string result = await response.Content.ReadAsStringAsync();
UserDto users = await response.Content.ReadAsJsonAsync<UserDto>();
List<UserDto> x2 = JsonConvert.DeserializeObject<List<UserDto>>(result);
The above getasync method gives me the below result and i am trying to deserialize it to object.
{
"users": [{
"id": "1",
"name": "ttest",
"permissions": [
"add",
"edit",
"delete"
]
}]
}
Error:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type 'System.Collections.Generic.List`1[****.Models.UserDto]'
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.
I get such JSON and want to deserialize it into my C# object. But this ends up in an error that cannot deserialize. Can I get help in fixing this?
In your JSON, Users JArray is inside a JObject, so to convert your JSON string you need List<User> inside a RootObject class like,
public class User
{
public string id { get; set; }
public string name { get; set; }
public List<string> permissions { get; set; }
}
public class Root
{
public List<User> users { get; set; }
}
Deserialize like,
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(result);
.NETFIDDLE

How do I parse json objects so that I can get all the values correctly

So I got this JSON string which looks like this:
{"success":false,"errors":[{"name":["Username "admin" has already been taken."],"email":["Email is not a valid email address."]}],"data":[]}
or, more readably:
{
"success": false,
"errors": [
{
"name": [
"Username "admin" has already been taken."
],
"email": [
"Email is not a valid email address."
]
}
],
"data": []
}
And I want to parse it in a way where I can get all the items in "errors" no matter the name of the error or value. Because the objects inside "errors" aren't always going to be "name" and "email" there might be different ones, but they will always be structured like that.
I managed to get this far:
var theObject = (JObject)JsonConvert.DeserializeObject(theJsonString);
And the goal would be to make it into a dictionary where I could get the name and the value of the error. Or just the name and value as one string would also work.
Essentially getting a collection of all the errors.
UPDATE
I tried deserializing it into it's own object
var theObject = JsonConvert.DeserializeObject<ResponseObject>(responseString);
Where the model looks like this
public class ResponseObject
{
[JsonProperty("success")]
public bool Success { get; set; }
//[JsonProperty("errors")]
//public Error[] Errors { get; set; }
[JsonProperty("errors")]
public Dictionary<string, List<string>> errors { get; set; }
[JsonProperty("data")]
public object[] Data { get; set; }
}
Which then throws this error
{"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'System.Collections.Generic.Dictionary2[System.String,System.Collections.Generic.List1[System.String]]'
because the type requires a JSON object (e.g. {"name":"value"}) to
deserialize correctly.\r\nTo 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.\r\nPath 'errors', line 1,
position 27."}
Errors is a List<Dictionary<string, List<string>>>
It looks like this:
"errors": [ <--
{
"1": [
"Username "admin" has already been taken."
],
"2": [
"Email is not a valid email address."
]
}
] <--
,
not a Dictionary<string, List<string>> that will llok like :
"errors":
{
"1": [
"Username "admin" has already been taken."
],
"2": [
"Email is not a valid email address."
]
},
A easy solutution for you would be:
If u have Visual Studio open it.
Copy ur Json Code.
Click on this and it generate your Code automatically for you :)
click here
Edit -> Import Json
Good Luck! :)
Sometimes it can be happen that he choose a "false" Datatype, but on ur litte json u will be fine.
This would be the output:
public class Rootobject
{
public bool success { get; set; }
public Error[] errors { get; set; }
public object[] data { get; set; }
}
public class Error
{
public string[] name { get; set; }
public string[] email { get; set; }
}

Deserialize JSON in c# - what is wrong?

I'm trying without success to deserialize this JSON in c#:
{
"settings": {
"path": "http:\/\/www.igormasin.it\/fileuploads\/tanja_23a6id"
},
"files": [{
"file": "\/IMG_0992-Edit_a.jpg"
}, {
"file": "\/IMG_1024-Edit_a.jpg"
}, {
"file": "\/IMG_1074-Edit_a.jpg"
}, {
"file": "\/Untitled-1.jpg"
}]
}
my code:
public class JsonTxt
{
public IList<string> settings { get; set; }
public IList<string> files { get; set; }
}
downloadstring contains the Json text:
var deserialized = JsonConvert.DeserializeObject<JsonTxt>(downloadString);
Console.WriteLine("*************************************************");
Console.WriteLine(deserialized.settings[0].ToString());
Console.WriteLine(deserialized.files.Count);
exception:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g.
{"name":"value"}) into type 'System.Collections.Generic.IList`1[System.String]' 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.
Path 'settings.path', line 1, position 20.'
I am not able to understand the error, and what I am suposed to do.. From what I understand IList is wrong, but what else would be the correct thing to write?
Your class structure needs to be something like this:
public class JsonTxt
{
public Settings Settings { get; set; }
public IList<File> Files { get; set; }
}
public class Settings
{
public string Path { get; set; }
}
public class File
{
public string File { get; set; }
}
Settings is an object, not a collection, and Files is a collection of objects not strings.
Your class type expect IList settings :
public class JsonTxt
{
public IList<string> settings { get; set; }
public IList<string> files { get; set; }
}
but in the json you provide is an object
"settings": {
"path": "http:\/\/www.igormasin.it\/fileuploads\/tanja_23a6id"
},
you should change JsonText attributes type to match with your JSON

Convert complex JSON to Generic List using Newtonsoft

Below is a Json :
[{
"Result": {
"description": "Application Security Supp Specialist",
"code": "40000003"
}
}, {
"Result": {
"description": "Gvt Cyber Intelligence Specialist",
"code": "40001416"
}
}, {
"Result": {
"description": "Gvt Record Retention Specialist",
"code": "40001428"
}
}]
And below is the class structure which i have created as i need to fill this into a C# object.
I am trying to create a collection of RulesEngineOutput and fill it with the json contents.
public class RulesEngineOutput
{
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
}
public class RulesEngineOutputCollection
{
public IEnumerable<RulesEngineOutput> ProbableRoles { get; set; }
}
I am trying to achieve this using below code :
var bodyJson = JsonConvert.SerializeObject(bodyString);
RulesEngineOutputCollection result = new RulesEngineOutputCollection();
foreach (var item in bodyJson)
{
result = JsonConvert.DeserializeObject<RulesEngineOutputCollection>(item.ToString());
}
But this is throwing exception as the item gets a char, what i am thinkiong is that i need to pass a JSON object in the loop but i am not able to get one.
Everytime i get is a JSON string.
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'RulesEngineOutputCollection' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo 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.
The problem is that you have an intermediary object between your RulesEngineOutput and your collection. You need to restructure your objects as such:
public class RulesEngineOutput
{
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
}
public class RulesEngineOutputResult
{
public RulesEngineOutput Result { get; set; }
}
public class RulesEngineOutputCollection
{
public IEnumerable<RulesEngineOutputResult> ProbableRoles { get; set; }
}
And then when you have this restructuring done, you can deserialize directly to your RulesEngineOutputCollection instead of to an object and iterating and deserializing again.
result = JsonConvert.DeserializeObject<RulesEngineOutputCollection>(bodyString);
Thanks a lot Max,Nathan and others. So finally i made some changes in code and below is the code which i changed tomake the things work :
var jToken = JObject.Parse(responseContent);
var bodyString = jToken.SelectToken("body");
var bodyJson = JsonConvert.SerializeObject(bodyString);
List<RulesEngineOutput> result = new List<RulesEngineOutput>();
try
{
foreach (var item in bodyString)
{
var formattedItem = item.SelectToken("Result");
var resultItem = JsonConvert.DeserializeObject<RulesEngineOutput>(formattedItem.ToString());
result.Add(resultItem);
}
}
Hope it helps others as well.
As Nathan Werry said, you have an object layered into another object and because of that, you cannot deserialize the data in the way you want it. However, you can work around that if you first create an array of these results and assign it later to your ProbableRoles property:
var rules = new RulesEngineOutputCollection
{
ProbableRoles = JsonConvert.DeserializeObject<Result[]>(bodyString).Select(r => r.Data).ToList()
};
public class Result
{
[JsonProperty("Result")]
public RulesEngineOutput Data { get; set; }
}
Everything else stays the same. You basically create a new list out of your array of results. I could also assign the Select() result directly (without calling .ToList()) but this ensures that the object actually has the data and not just a reference to an enumeration.

How to convert Json type with array to .net object?

I have JSON string:
// the coverage value is an array.
string jsonData = #"{
""plans"":
[
{
""plan_code"":""UL500"",
""plan_name"":""Unlimited 500M"",
""days"":1,
""limit"":500,
""coverage"":
[
{
""country"":""SE"",
},
{
""country"":""BZ""
}
]
},
{
""plan_code"":""UL1GB"",
""plan_name"":""Unlimited 1GB"",
""days"":1,
""limit"":1024,
""coverage"":
[
{
""country"":""SG"",
},
{
""country"":""JP""
}
]
}
]
}
";
and i'm parse by JsonConvert.DeserializeObject as sample code below:
try
{
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("", content);
var result = await response.Content.ReadAsStringAsync();
var tempRecords = JsonConvert.DeserializeObject<List<plan>>(result);
}
and then i'm get an error message:
"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[DAL.plan]' 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 'plans', line 1, position 9."
please show me a right way for this issue.
Here is the working code with the same JSON, from my console app:
public class Program
{
static void Main(string[] args)
{
string jsonData = "{\"plans\":[{\"plan_code\":\"UL500\",\"plan_name\":\"Unlimited 500M\",\"days\":1,\"limit\":500,\"coverage\":[{\"country\":\"SE\"},{\"country\":\"BZ\"}]},{\"plan_code\":\"UL1GB\",\"plan_name\":\"Unlimited 1GB\",\"days\":1,\"limit\":1024,\"coverage\":[{\"country\":\"SG\"},{\"country\":\"JP\"}]}]}";
var tempRecords = JsonConvert.DeserializeObject<RootObject>(jsonData);
}
}
public class RootObject
{
public List<plan> plans { get; set; }
}
public class plan
{
public string plan_code { get; set; }
public string plan_name { get; set; }
public int days { get; set; }
public int limit { get; set; }
public IList<Country> coverage { get; set; }
}
public class Country
{
public string country { get; set; }
}
I have created C# classes that suits your JSON structure.
As a note, I have modified the JSON you provided, as it seems to be not in the correct format.
The whole string represents an object with a property called "plans" that refers to your array. The string itself is not the array, so if you're trying to deserialize it as a List<T>, that's not going to work. You need to handle the fact that your desired array is wrapped by a JSON object.
This is a similar problem that I think explains it well.
The entity corresponding to the JSON format does not match. Your format is an object, and the object has an array of attributes, not List
Hello,I have just looked at your question, I found that you provided the json string, not the standard format json string. Here I am giving me a good json string, you can try it out。
{
"plans": [`enter code here`
{
"plan_code": "UL500",
"plan_name": "Unlimited500M",
"days": 1,
"limit": 500,
"coverage": [
{
"country": "SE"
},
{
"country": "BZ"
}
]
},
{
"plan_code": "UL1GB",
"plan_name": "Unlimited1GB",
"days": 1,
"limit": 1024,
"coverage": [
{
"country": "SG"
},
{
"country": "JP"
}
]
}
]
}

Categories

Resources