I am trying to retrieve data (just the phone number) from a nested JSON using Newtonsoft dll.
Json (request) looks something like this :
[{
"name": "sam",
"age": 19,
"Gender" : "F",
"Email" : "sam#test.com",
...
"PhoneNumber" :{
"CCode":"1",
"Area": "123",
"PhoneNum": "456-789",
"PhoneExtn": ""
}
...
}]
I have many more values in the json, but I need only phone number, so creating a Custom Class with above properties and using DeserializeObject on the above JSON string is not an option. However, I did try the below options:
dynamic jsonObj = JsonConvert.DeserializeObject(request);
var option1 = (string)jsonObj["PhoneNumber"]["CCode"];
var option2 = (string)jsonObj["PhoneNumber"][0]["CCode"];
//option3
PhoneNumberModel phone = JsonConvert.DeserializeObject<PhoneNumberModel>(jsonObj["PhoneNumber"].ToObject<string>());
//option4
PhoneNumberModel phone = JsonConvert.DeserializeObject<PhoneNumberModel>(jsonObj["PhoneNumber"][0].ToObject<string>());
Get these exceptions:
1. Cannot apply indexing with [] to an expression of type for first three options
2. Accessed JObject values with invalid key value: 0. Object property name expected for option 4.
I have tried many online solutions provided but none work. I am running out of options now.
Just define the properties that you need.
public class Person
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "PhoneNumber")]
public PhoneNumberModel { get; set; }
}
public class PhoneNumberModel
{
public int CCode { get; set;}
public int Area { get; set;}
public string PhoneNum { get; set; }
public string PhoneExtn { get; set; }
}
var person = JsonConvert.DeserializeObject<Person>(json);
var name = person.Name;
var phoneNumber = person.PhoneNumberModel;
Have you tried using the JsonConvert.DeserializeObject<T>(string) API but sending the whole request to it? Something like this:
PhoneNumberModel phone = JsonConvert.DeserializeObject<PhoneNumberModel>(request);
Newtonsoft ignores the missing properties in the target class.
You can get the PhoneNumber into your model like this:
PhoneNumberModel model =
JArray.Parse(json)[0]
.SelectToken("PhoneNumber")
.ToObject<PhoneNumberModel>();
Fiddle: https://dotnetfiddle.net/U21KfN
Related
I'm trying to retrieve all data from a JSON file to my C# application.
But now the problem is that the field "info" in my json file is sometimes from the type string but it can also be the type object.
{
[
{
"id":"147786",
"canUpdate":true,
"canDelete":true,
"canArchive":true,
"hasChildren":false,
"info": "Test"
},
{
"id":"147786",
"canUpdate":true,
"canDelete":true,
"canArchive":true,
"hasChildren":false,
"info": [{"id"="1","messages":"true"}]
}
]
}
well my model you can see here below, when there are only strings in my json file i can retrieve the data without any exception but when there are also objects in the info field then i get the error can't convert the value.
Is there a way to fix this on an easy way?
public string id { get; set; }
public string canUpdate { get; set; }
public string info { get; set; }
As an option you can define the info as dynamic:
public dynamic info { get; set; }
Example
Consider the following json string:
string json = #"
[
{ 'P1': 'X', 'P2': 'Y' },
{ 'P1': 'X', 'P2': [
{'P11':'XX', 'P22':'YY'},
{'P11':'XX', 'P22':'YY'}]
}
]";
You can define such model to deserialize it:
public class C
{
public string P1 { get; set; }
public dynamic P2 { get; set; }
}
And deserialize it like this:
var obj = JsonConvert.DeserializeObject<C[]>(json);
Note
If the number of dynamic properties is too much then usually there is no point in creating the class and the following code will be enough:
var obj = (dynamic)JsonConvert.DeserializeObject(json);
...and "beautiful" is sarcastic here.
When you call Active Campaign's list_view endpoint, and would like to get that in a json response, then this is the json response you get:
{
"0": {
"id": "4",
"name": "Nieuwsletter 1",
"cdate": "2018-11-22 03:44:19",
"private": "0",
"userid": "6",
"subscriber_count": 2901
},
"1": {
"id": "5",
"name": "Newsletter 2",
"cdate": "2018-11-22 05:02:41",
"private": "0",
"userid": "6",
"subscriber_count": 2229
},
"2": {
"id": "6",
"name": "Newsletter 3",
"cdate": "2018-11-22 05:02:48",
"private": "0",
"userid": "6",
"subscriber_count": 638
},
"result_code": 1,
"result_message": "Success: Something is returned",
"result_output": "json"
}
Now how would I ever be able to deserialize this to an object? Doing the normal Edit => Paste Special => Paste JSON As Classes gives me an output where I end up with classes that named _2.
Also, JsonConvert throws the following error: Accessed JObject values with invalid key value: 2. Object property name expected. So it is not really able to deserialize it either. I tried to use dynamic as object type to convert to.
The only thing I can think of now is replacing the first { by [ and the last } by ], then remove all the "1" : items and then remove the last 3 properties. After that I have a basic array which is easy convertable. But I kind of hope someone has a better solution instead of diving deep into the string.indexOf and string.Replace party...
If your key/value pair is not fixed and data must be configurable then Newtonsoft.json has one feature that to be used here and that is [JsonExtensionData]. Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case key/value pair with 0,1,2,3.......N have dynamic data so your class will be
So create one property that collects all of your dynamic key/value pair with the attribute [JsonExtensionData]. And below I create that one with name DynamicData.
class MainObj
{
[JsonExtensionData]
public Dictionary<string, JToken> DynamicData { get; set; }
public int result_code { get; set; }
public string result_message { get; set; }
public string result_output { get; set; }
}
And then you can deserialize your JSON like
string json = "Your json here"
MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json);
Edit:
If you want to collect your dynamic key's value to class then you can use below the class structure.
class MainObj
{
[JsonExtensionData]
public Dictionary<string, JToken> DynamicData { get; set; }
[JsonIgnore]
public Dictionary<string, ChildObj> ParsedData
{
get
{
return DynamicData.ToDictionary(x => x.Key, y => y.Value.ToObject<ChildObj>());
}
}
public int result_code { get; set; }
public string result_message { get; set; }
public string result_output { get; set; }
}
public class ChildObj
{
public string id { get; set; }
public string name { get; set; }
public string cdate { get; set; }
public string _private { get; set; }
public string userid { get; set; }
public int subscriber_count { get; set; }
}
And then you can deserialize your JSON like
MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json);
And then you can access each of your deserialized data like
int result_code = mainObj.result_code;
string result_message = mainObj.result_message;
string result_output = mainObj.result_output;
foreach (var item in mainObj.ParsedData)
{
string key = item.Key;
ChildObj childObj = item.Value;
string id = childObj.id;
string name = childObj.name;
string cdate = childObj.cdate;
string _private = childObj._private;
string userid = childObj.userid;
int subscriber_count = childObj.subscriber_count;
}
I'd recommend JObject from the Newtonsoft.Json library
e.g. using C# interactive
// Assuming you've installed v10.0.1 of Newtonsoft.Json using a recent version of nuget
#r "c:\Users\MyAccount\.nuget\.nuget\packages\Newtonsoft.Json\10.0.1\lib\net45\Newtonsoft.Json.dll"
using Newtonsoft.Json.Linq;
var jobj = JObject.Parse(File.ReadAllText(#"c:\code\sample.json"));
foreach (var item in jobj)
{
if (int.TryParse(item.Key, out int value))
{
Console.WriteLine((string)item.Value["id"]);
// You could then convert the object to a strongly typed version
var listItem = item.Value.ToObject<YourObject>();
}
}
Which outputs:
4
5
6
See this page for more detail
https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
I'm trying to deserialize a JSON response from WooCommerce with RestSharp.
I've been crawling this site for similar posts, but haven't found any solution.
My JSON (simplified)
[
{
"id":1,
"name":"product 1",
},
{
"id":2,
"name":"product 2",
}
]
Which translates into C# like this:
public class ProductResponse
{
public List<Product> products { get; set; }
}
public class Product
{
public int id { get; set; }
public string name { get; set; }
}
And is called like this
var response = client.Execute<ProductResponse>(request);
But it doesn't work, as the array of products doesn't have a name.
If the JSON is changed to
{
"products":
[
{
"id":1,
"name":"product 1",
},
{
"id":2,
"name":"product 2",
}
]
}
It works like a charm. Unfortunately I'm not able to change the JSON-format.
So how do I solve this?
Thanks in advance
You can annotate your product class to tell RestSharp which property is which:
public class Product
{
[DeserializeAs(Name = "id")]
public int id { get; set; }
[DeserializeAs(Name = "name")]
public string name { get; set; }
}
Then:
var response = client.Execute<List<Product>>(request);
You should now have a List<Product> with two correctly populated entries.
Original answer for posterity:
I don't have an answer for RestSharp (yet) but you could achieve this easily with Newtonsoft JSON if you can use that.
You can use the JsonProperty annotation like so:
public class Product
{
[JsonProperty("id")]
int id { get; set; }
[JsonProperty("name")]
string name { get; set; }
}
Then:
var products = JsonConvert.DeserializeObject<List<Product>>(json);
I think your deserialization actually should be List<Product> rather than ProductResponse.
E.g.
var response = client.Execute<List<Product>>(request);
Console.WriteLine("id = " + response[0].id) // id = 1
Console.WriteLine("name = " + response[0].name) // name = product 1
Console.WriteLine("id = " + response[1].id) // id = 2
Console.WriteLine("name = " + response[1].name) // name = product 2
So there is nothing wrong with the JSON string, I think the problem is you are expecting an object of type ProductResponse, where as your JSON string is an array/List of type Product.
I need a little help with json deserialization. It's the first time I'm using Json, so I have just a little knowledge about it.
I get the following string using a webclient:
[{"name": "somename", "data": [[72, 1504601220], [null, 1504601280], ..., [125, 1504605840]]}]
and tried to serialize it with
JsonConvert.DeserializeObject<TestObject>(jsonstring)
My class looks like this:
public class TestObject
{
[JsonProperty(PropertyName = "name")]
public string TargetName { get; set; }
[JsonProperty(PropertyName = "data"]
public List<?????> DataPoints {get; set;}
}
How do I need to design my class to get the data values in some kind of collection so each entry contains the two values inside a bracket?
Thx for your patience and help!
Your data is a list of arrays containing nullable integers (by the looks of it)
[JsonProperty(PropertyName = "data"]
public List<int?[]> DataPoints {get; set;}
Try this website: http://json2csharp.com/
This website can save a lot of your time if you have just a plain JSON text. It helps you convert it to C# object, although you still have to double check it.
var data = "[{\"name\": \"somename\", \"data\": [[72, 1504601220], [null, 1504601280], [125, 1504605840]]}]";
var obj = JsonConvert.DeserializeObject<List<TestObject>>(data);
public class TestObject
{
[JsonProperty(PropertyName = "name")]
public string TargetName { get; set; }
[JsonProperty(PropertyName = "data")]
public List<int?[]> DataPoints { get; set; }
}
There is a some solution for this, C# 7.0 also supports ValueTuple such as this example.
List<(int? ,int?)> DataPoints { get; set; }
// if it not work try this.
List<List<int?>> DataPoints { get; set; }
If your json inner array elements count is equal to 2, so can assume to you use the value tuples.
Assume it is helpful for you.
I've been stuck on this for awhile. I have a JSON response sending me keys that include periods. For example: "cost_center.code"
How can I get this into my object? I'm not getting any errors but the value is just coming in as null and isn't being deserialized into my class.
Here's my classes:
public class Result
{
public string company { get; set; }
public string first_name { get; set; }
public string email { get; set; }
public string employee_id { get; set; }
public string last_name { get; set; }
[DeserializeAs(Name="cost_center.code")]
public string cost_center { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
Here's the JSON response:
{
"result": [
{
"company": "My Company",
"first_name": "First",
"email": "example#fakeaddress.com",
"employee_id": "123456789",
"last_name": "Last",
"cost_center.code": "12345"
}
]
}
I execute with:
var response = client.Execute<List<RootObject>>(request);
// this returns null
Console.WriteLine(response.Data[0].result[0].cost_center);
// all other values return fine ex:
Console.WriteLine(response.Data[0].result[0].company);
I've tried both with and without the DeserializeAs. I'm not sure its even working. Am I using this property incorrectly? Is it a container issue with the List?
Edited and accepted the answer below to use JsonProperty. For others who may come along this was the solution.
Added JSON.net nuget.
using Newtonsoft.Json;
Set the JsonProperty as described:
[JsonProperty("cost_center.code")]
Changed my execute to:
var response = client.Execute(request);
Then deserialized it like this:
var jsonResponse = JsonConvert.DeserializeObject<RootObject>(response.Content);
Afterwards I can access the value:
Console.WriteLine(jsonResponse.result[0].CostCenter
Do the following with properties having period in their names :
[JsonProperty("cost_center.code")]
public string CostCenter{ get; set; }
It should work
If you want to user RestSharp natively or couldn't get the Newtonsoft.Json.JsonSerializer support to work (which I couldn't), they just added support for proper deserialization of properties with dots in their names as of 106.1.0.
See my response here: Accessing properties with a dot in their name