I have the following JSON (I can't change the incoming JSON as it is from a 3rd party system):
{
"id": 23,
"userName":"test#test.com",
"tags":
{
"Employee ID":
{
"name":"Employee ID",
"value":"123456789"
},
"Job Family":
{
"name": "Job Family",
"value": "Accounting and Finance"
}
}
}
First, I tried to deserialize using this class structure:
public class User
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("username")]
public string Email { get; set; }
[JsonProperty("tags")]
public TagsJson Tags { get; set; }
}
public class TagsJson
{
[JsonProperty("tags")]
public List<Tag> Tags { get; set; }
}
public class Tag
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}
In using Newtonsoft's JsonConvert.DeserializeObject(json);, the User.Tags property is always empty. This is obviously because there are no "Tags" under the "Tags" attribute.
Yet, if I change the User class as follows...
public class User
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("tags")]
public List<Tag> Tags { get; set; }
// I even tried Tag[] instead of List<Tag> here
}
...I get the following error:
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[Tag]' because the type requires
a JSON array (e.g. [1,2,3]) to deserialize correctly.
Any suggestions on creating the User class to allow it to deserialize correctly would be greatly appreciated.
EDIT
So this may or may not be the best answer, but it works. The tags coming in will be one of a dozen different names. So I created a Tags class with a property for each of the 12 possibilites. Since none are required, any of them that do appear will get populated. Here's my adjusted User, Tags (formerly TagsJson) and Tag classes below - but I'm definitely interested in a better solution.
public class User
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("username")]
public string Email { get; set; }
[JsonProperty("tags")]
public Tags AllTags { get; set; }
}
public class Tags
{
[JsonProperty("Employee ID")]
public Tag EmployeeID { get; set; }
[JsonProperty("Job Family")]
public Tag JobFamily { get; set; }
// ... and 10 more properties for additional tags that may appear but are not required
}
public class Tag
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}
The suggested answer of this question does not work in my case because the JSON is not an array or a collection but a list of unique attribute names with a name/value pairing.
Well using the Visual Studio paste Json as classes yields...
public class Rootobject
{
public int id { get; set; }
public string userName { get; set; }
public Tags tags { get; set; }
}
public class Tags
{
[JsonProperty(PropertyName = "Employee ID")]
public EmployeeID EmployeeID { get; set; }
[JsonProperty(PropertyName = "Job Family")]
public JobFamily JobFamily { get; set; }
}
public class EmployeeID
{
public string name { get; set; }
public string value { get; set; }
}
public class JobFamily
{
public string name { get; set; }
public string value { get; set; }
}
I had to add in the JsonProperty attributes myself. However I think a better solution would be...
public class Rootobject2
{
public int id { get; set; }
public string userName { get; set; }
public IDictionary<string, NameValuePair> tags { get; set; }
}
public class NameValuePair
{
public string name { get; set; }
public string value { get; set; }
}
Although the paste Json as classes was a good starting point to easily copy and paste the code into the favoured solution.
Some test code...
string json = Resource1.String1;
Rootobject test = JsonConvert.DeserializeObject<Rootobject>(json);
Rootobject2 test2 = JsonConvert.DeserializeObject<Rootobject2>(json);
Not sure your JSON is correct but why is there space in your property name Employee ID or Job Family. Fix those in Tags class and we are good to go.
public class EmployeeID
{
public string name { get; set; }
public string value { get; set; }
}
public class JobFamily
{
public string name { get; set; }
public string value { get; set; }
}
public class Tags
{
public EmployeeID __invalid_name__Employee ID { get; set; }
public JobFamily __invalid_name__Job Family { get; set; }
}
public class User
{
public int id { get; set; }
public string userName { get; set; }
public Tags tags { get; set; }
}
This is what i got from json2csharp.com
Your JSON shows that your tags object is an Object - not an Array. You cannot deserialize an Object into a C# List because they are different structures.
If the keys in tags are dynamic/changing, then perhaps try
[JsonProperty("tags")]
Dictionary<string, string> Tags { get; set; }
Edit
It appears that your JSON is not well-formed; if you aren't able to modify it, you might have to use a custom JsonConverter.
Related
I am trying to take this JSON:
{
"title":"string",
"description":"string",
"date":"2021-04-19T01:05:38.000Z",
"image":"url",
"images":[
"url1",
"url2"
],
"attributes":{
"phonebrand":"x",
"phonecarrier":"y",
"forsaleby":"z",
"price":12345,
"location":"daLocation",
"type":"OFFERED"
},
"url":"url to listing"
}
And convert it into this C# Object:
public class Listing {
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("date")]
public DateTime? Date { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("images")]
public string[] Images { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("price")]
public decimal Price { get; set; }
[JsonProperty("locationId")]
public int LocationId { get; set; }
[JsonProperty("categoryId")]
public int CategoryId { get; set; }
[JsonProperty("sortByName")]
public string SortByName { get; set; }
[JsonProperty("q")]
public string Q { get; set; }
[JsonProperty("location")]
public string Location { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("forsaleby")]
public string ForSaleBy { get; set; }
[JsonProperty("fulfillment")]
public string Fulfillment { get; set; }
[JsonProperty("payment")]
public string Payment { get; set; }
[JsonProperty("phonebrand")]
public string? PhoneBrand { get; set; }
[JsonProperty("phonecarrier")]
public string? PhoneCarrier { get; set; }
}
My problem is, I'm trying to deserialize properties like price and phonebrand but those properties are under an object in the JSON. So when I try to deserialize them like this, those properties can't be found and are set as null. How can I deserialize those properties without changing my C# Class to include an Attributes class? I want to do this because I think that it is a cleaner/better design compared the JSON I'm taking in.
I suggest two approaches that are very explicit and easy to follow for the next developer looking at the code.
Two classes
creating a intermediate dto class that is used for deserialisation and then creating the business logic object from that intermediate object.
var withAttributes = Deserialise<ListingDto>();
var flatObject = new Listing(withAttributes);
One class
You could provide accessors at the top level which dip into the subclasses.
public class Listing
{
public AttributesDto Attributes {get; set}
...
public string Url => Attributes.Url; // Maybe '?.Url'
}
I have the following Json returned from iTunes (I have replaced some details for privacy such as username and review content)
{"feed":{"author":{"name":{"label":"iTunes Store"}, "uri":{"label":"http://www.apple.com/uk/itunes/"}}, "entry":[
{"author":{"uri":{"label":"https://itunes.apple.com/gb/reviews/ID"}, "name":{"label":"Username"}, "label":""}, "im:version":{"label":"3.51"}, "im:rating":{"label":"4"}, "id":{"label":"12345"}, "title":{"label":"Review title"}, "content":{"label":"Review contents", "attributes":{"type":"text"}}, "link":{"attributes":{"rel":"related", "href":"https://itunes.apple.com/gb/review?reviewid"}}, "im:voteSum":{"label":"0"}, "im:contentType":{"attributes":{"term":"Application", "label":"Application"}}, "im:voteCount":{"label":"0"}},
// more entries ...
I want to deserialize this into a class. I only need the Review Title, Review contents, and the "im:rating" (which is the number of stars). However, I'm struggling due to the nested Json and the use of keys of how to extract this data. So far I have created a class ready to deserialize, and I have AppStoreData appStoreData = JsonConvert.DeserializeObject<AppStoreData>(stringResult); to deserialize it
public class AppStoreData {
}
My problem is that I don't know what to put inside the class to get the info I need from the Json. I have tried things such as:
public string title {get; set;}
public string content {get; set;}
public string imrating {get; set;}
However this doesn't work. I also think im:rating is an invalid name in C#.
Can anyone please help? Thank you
To get around the issue with im:rating you can use a JsonProperty attribute
[JsonProperty("im:rating")]
public Id ImRating { get; set; }
The issue with converting things like Label to string property is that it's not a string but an object in the input file.
You need something like
[JsonProperty("title")]
public Id Title { get; set; }
where Id is a class
public class Id
{
[JsonProperty("label")]
public string Label { get; set; }
}
Or write a deserializer that converts it to string for you.
I would suggest trying out one of many free code generators like https://app.quicktype.io/?l=csharp or http://json2csharp.com/ to get a headstart and edit everything to your liking afterwards.
I suggest using json2csharp to convert the json to c# model and change the invalid attributes by adding JsonProperty
public class Name
{
public string label { get; set; }
}
public class Uri
{
public string label { get; set; }
}
public class Author
{
public Name name { get; set; }
public Uri uri { get; set; }
}
public class Uri2
{
public string label { get; set; }
}
public class Name2
{
public string label { get; set; }
}
public class Author2
{
public Uri2 uri { get; set; }
public Name2 name { get; set; }
public string label { get; set; }
}
public class ImVersion
{
public string label { get; set; }
}
public class ImRating
{
public string label { get; set; }
}
public class Id
{
public string label { get; set; }
}
public class Title
{
public string label { get; set; }
}
public class Attributes
{
public string type { get; set; }
}
public class Content
{
public string label { get; set; }
public Attributes attributes { get; set; }
}
public class Attributes2
{
public string rel { get; set; }
public string href { get; set; }
}
public class Link
{
public Attributes2 attributes { get; set; }
}
public class ImVoteSum
{
public string label { get; set; }
}
public class Attributes3
{
public string term { get; set; }
public string label { get; set; }
}
public class ImContentType
{
public Attributes3 attributes { get; set; }
}
public class ImVoteCount
{
public string label { get; set; }
}
public class Entry
{
public Author2 author { get; set; }
[JsonProperty(PropertyName = "im:version")]
public ImVersion imversion { get; set; }
[JsonProperty(PropertyName = "im:rating")]
public ImRating imrating { get; set; }
public Id id { get; set; }
public Title title { get; set; }
public Content content { get; set; }
public Link link { get; set; }
[JsonProperty(PropertyName = "im:voteSum")]
public ImVoteSum imvoteSum { get; set; }
[JsonProperty(PropertyName = "im:contentType")]
public ImContentType imcontentType { get; set; }
[JsonProperty(PropertyName = "im:voteCount")]
public ImVoteCount imvoteCount { get; set; }
}
public class Feed
{
public Author author { get; set; }
public List<Entry> entry { get; set; }
}
public class RootObject5
{
public Feed feed { get; set; }
}
Once the model is ready you can use JsonConvert.DeserializeObject to convert the JSON to c# object
using (StreamReader r = new StreamReader(filepath)) {
string json = r.ReadToEnd();
var newEmps = JsonConvert.DeserializeObject<RootObject5>(json);
Console.WriteLine(newEmps.feed.entry[0].imvoteCount.label);
}
I get the following JSON response.
[
{
"Issue": {
"ID": 80,
"Name": "Cold",
"Accuracy": 90,
"Icd": "J00",
"IcdName": "Acute nasopharyngitis [common cold]",
"ProfName": "Common cold",
"Ranking": 1
},
"Specialisation": [
{
"ID": 15,
"Name": "General practice",
"SpecialistID": 0
}
]
}
]
I tried to follow the instructions given here. But I can't seem to fit that solution here. And in the documentation is explained only the scenario where you already have the class predefined. Any help?
Presumptions
Your question is not even clear. What are you asking? I presume you are asking how to make a C# class from that JSON?
Solution
Firstly, the JSON is an array (if its top-level tags are [] its an array itself. If its top level is {} then its a single object.
So what you have is an array returned with one result inside of it.
Going to json2csharp and pasting your code gives this:
public class Issue
{
public int ID { get; set; }
public string Name { get; set; }
public int Accuracy { get; set; }
public string Icd { get; set; }
public string IcdName { get; set; }
public string ProfName { get; set; }
public int Ranking { get; set; }
}
public class Specialisation
{
public int ID { get; set; }
public string Name { get; set; }
public int SpecialistID { get; set; }
}
public class RootObject
{
public Issue Issue { get; set; }
public List<Specialisation> Specialisation { get; set; }
}
And you can see its created a RootObject almost indicating it is a single object, but you will need to deserialize this as a List<RootObject> not just RootObject.
So in C# that would be var result = JsonConvert.DeserializeObject<List<RootObject>>(theJsonString);
You should have a strongly typed c# class ready for your Json Response to be deserialized into... Json Utils has a generator to use, it came up with this:
public class Issue
{
[JsonProperty("ID")]
public int ID { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Accuracy")]
public int Accuracy { get; set; }
[JsonProperty("Icd")]
public string Icd { get; set; }
[JsonProperty("IcdName")]
public string IcdName { get; set; }
[JsonProperty("ProfName")]
public string ProfName { get; set; }
[JsonProperty("Ranking")]
public int Ranking { get; set; }
}
public class Specialisation
{
[JsonProperty("ID")]
public int ID { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("SpecialistID")]
public int SpecialistID { get; set; }
}
public class RootObject
{
[JsonProperty("Issue")]
public Issue Issue { get; set; }
[JsonProperty("Specialisation")]
public IList<Specialisation> Specialisation { get; set; }
}
Then use
RootObject jsonAsCSharpClass = JsonConvert.DeserializeObject<RootObject>(jsonResponse);
I'm not 100% sure this class is good for you though, i have never some across a response where the root response is an array, without defining a root property first, see how it starts with "[" instead of { ??? You may want to also try
List<RootObject> jsonAsCSharpClass = JsonConvert.DeserializeObject<List<RootObject>>(jsonResponse);
Or wait for someone with more knowledge on the subject to come along...
I am getting the below JSON in response from a REST API.
{
"data":{
"id":123,
"zoneid":"mydomain.com",
"parent_id":null,
"name":"jaz",
"content":"172.1 6.15.235",
"ttl":60,
"priority":null,
"type":"A",
"regions":[
"global"
],
"system_record":false,
"created_at":"2017-09-28T12:12:17Z",
"updated_at":"2017-09-28T12:12:17Z"
}
}
and trying to resolve using below code but that doesn't result in a correctly deserialized type.
var model = JsonConvert.DeserializeObject<ResponseModel>(response);
below is a class according the field I received in JSON response.
public class ResponseModel
{
public int id { get; set; }
public string zone_id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public int priority { get; set; }
public string type { get; set; }
public string[] regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
What is missing?
You're missing a wrapper class.
public class Wrapper
{
public ResponseModel data {get;set}
}
and then do:
var model = JsonConvert.DeserializeObject<Wrapper>(response).data;
to get the instance of your ResponseModel out the data property.
You can deduct this from your json:
{ "data":
{ "id":123, /*rest omitted */ }
}
The type that will receive this JSON needs to have a property named data. The suggested Wrapper class acts as that type.
According to json2csharp website, your model seems to be incorrect. Try this one :
public class ResponseModel
{
public int id { get; set; }
public string zoneid { get; set; }
public object parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public object priority { get; set; }
public string type { get; set; }
public List<string> regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
public class RootObject
{
public ResponseModel data { get; set; }
}
Here a cool trick you can do in Visual Studio 2015-2017 where it generates the the correct class if you just copy the JSON (ctrl + c).
You need to create a new class in visual studio and once inside the class go to Edit menu -> Paste special -> paste JSON As Classes.
Steps to generate json class
This will generate the C# object for that json for you and save you all the hassle :)
Your model does not match your response - it matches the data property. Simply wrap another object round it
public class ResponseData
{
public ResponseModel Data {get; set; {
}
and then
var model = JsonConvert.DeserializeObject<ResponseData>(response);
With C#, I try without success to de-serialize this json content :
{
"code":200,
"message":"OK",
"name":"The name",
"description":"The description",
"tags":{
"0.1.3":{
"date":"2015-03-11",
"author":"SOMEONE",
},
"0.1.2":{
"date":"2015-03-11",
"author":"SOMEONE",
}
}
}
You have noticed, there's a list of "tag" objects, but I have not a table.
Beginning of the target classes :
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
**How can I handle tags entries ?**
}
[DataContract]
public class Tag
{
[DataMember]
public string date { get; set; }
[DataMember]
public string author { get; set; }
}
If you're using JSON.NET, then you can have the following:
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public Dictionary<string, Tag> tags { get; set; }
}
[DataContract]
public class Tag
{
[DataMember]
public string date { get; set; }
[DataMember]
public string author { get; set; }
}
Which then you would use the following way (assuming responseString contains your JSON):
Project project = JsonConvert.DeserializeObject<Project>(responseString);
foreach (KeyValuePair<string, Tag> tag in project.tags)
{
Debug.WriteLine("Version: {0}", tag.Key);
Debug.WriteLine("Date: {0}", tag.Value.date);
Debug.WriteLine("Author: {0}", tag.Value.author);
}
The JSON input is valid according to RFC 4627 (JSON specfication).
http://www.freeformatter.com/json-validator.html
JSON sturcture is based on Key Value pair. Correct JSON format is like:
{
"object":{
"DataMember1":"String content",
"DataMember2":"String content",
"DataMember3":"String content"
},
"object2":{
"DataMember1":"String content",
"DataMember2":"String content"
}
}
Goto basics
To check your json structure you can validate from click here
Hmm, I was able to deserialize:
Newtonsoft.Json.JsonConvert.DeserializeObject<Project>(json);
However, here is my class definition:
public class Project
{
public string code { get; set; }
public string message { get; set; }
public string name { get; set; }
public string description { get; set; }
public Dictionary<string,Tag> tags { get; set; }
}
public class Tag
{
public string date { get; set; }
public string author { get; set; }
}
Thanks to Arturo Torres Sánchez. To get the "tag" entries, the declaration must be :
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public Dictionary<string, Tag> tags { get; set; }
}
And the most important, I must modify the default settings and use the new settings when I create the instance of DataContractJsonSerializer.
DataContractJsonSerializerSettings settings =
new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(typeof(Project), settings);
Project results = (Project)serializer.ReadObject(ms);
Without the settings.UseSimpleDictionaryFormat = true; tag's object count is 0.