Newtonsoft JSON Deserialize
You can implement a class that holds the fields you have in your JSON
class MyData
{
public string t;
public bool a;
public object[] data;
public string[][] type;
}
and then use the generic version of DeserializeObject:
MyData tmp = JsonConvert.DeserializeObject<MyData>(json);
foreach (string typeStr in tmp.type[0])
{
// Do something with typeStr
}
Documentation: Serializing and Deserializing JSON
Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?)
If you just need to get a few items from the JSON object, I would use Json.NET's LINQ to JSON JObject
class. For example:
JToken token = JObject.Parse(stringFullOfJson);
int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");
I like this approach because you don't need to fully deserialize the JSON object. This comes in handy with APIs that can sometimes surprise you with missing object properties, like Twitter.
Documentation: Serializing and Deserializing JSON with Json.NET and LINQ to JSON with Json.NET
How to deserialize complex JSON with Newtonsoft?
This is indeed a complex schema so it's not easy to generate DTOs automatically. For that reason, you shouldn't use custom names for the properties. It makes it even harder to find problems.
- The
near_earth_objects
section is actually a dictionary of daily observations. Instead of creating anear_earth_objects
class it's better to use aDictionary<string,Observation[]>
. links
contains links to the current, next and previous pages in the feed. This means you can actually create one class and reuse it both at the root level and in daily observations
You can use a DTO generator tool to get started but the result will need modifications. Tools won't be able to recognize that near_earth_objects
is a dictionary and can easily end up creating new types for every entry.
The DTOs
Using your JSON sample I created initial classes using Visual Studio's Paste as Json
and then modified them to work properly.
public class Rootobject
{
public PageLinks links { get; set; }
public int element_count { get; set; }
public Dictionary<string,Observation[]> near_earth_objects { get; set; }
}
public class PageLinks
{
public string? next { get; set; }
public string? prev { get; set; }
public string self { get; set; }
}
The Observation
class uses the same PageLinks
class for the links
property:
public class Observation
{
public PageLinks links { get; set; }
public string id { get; set; }
public string neo_reference_id { get; set; }
public string name { get; set; }
public string nasa_jpl_url { get; set; }
public float absolute_magnitude_h { get; set; }
public Estimated_Diameter estimated_diameter { get; set; }
public bool is_potentially_hazardous_asteroid { get; set; }
public Close_Approach_Data[] close_approach_data { get; set; }
public bool is_sentry_object { get; set; }
}
The rest of the classes require no modification:
public class Estimated_Diameter
{
public Kilometers kilometers { get; set; }
public Meters meters { get; set; }
public Miles miles { get; set; }
public Feet feet { get; set; }
}
public class Kilometers
{
public float estimated_diameter_min { get; set; }
public float estimated_diameter_max { get; set; }
}
public class Meters
{
public float estimated_diameter_min { get; set; }
public float estimated_diameter_max { get; set; }
}
public class Miles
{
public float estimated_diameter_min { get; set; }
public float estimated_diameter_max { get; set; }
}
public class Feet
{
public float estimated_diameter_min { get; set; }
public float estimated_diameter_max { get; set; }
}
public class Close_Approach_Data
{
public string close_approach_date { get; set; }
public string close_approach_date_full { get; set; }
public long epoch_date_close_approach { get; set; }
public Relative_Velocity relative_velocity { get; set; }
public Miss_Distance miss_distance { get; set; }
public string orbiting_body { get; set; }
}
public class Relative_Velocity
{
public string kilometers_per_second { get; set; }
public string kilometers_per_hour { get; set; }
public string miles_per_hour { get; set; }
}
public class Miss_Distance
{
public string astronomical { get; set; }
public string lunar { get; set; }
public string kilometers { get; set; }
public string miles { get; set; }
}
Testing the model
With this model, the following test passes:
[Fact]
public async Task GetFeed()
{
var client = new HttpClient();
var url = "http://www.neowsapp.com/rest/v1/feed?start_date=2021-12-09&end_date=2021-12-12&detailed=false&api_key=Na1sKwJGK1HVeOF4Yx8aLNp4u8ygT5GSSMF26HQ2";
var feed = await client.GetFromJsonAsync<Rootobject>(url);
Assert.Equal(76,feed.element_count);
var allObservations = feed.near_earth_objects
.SelectMany(p => p.Value)
.ToList();
Assert.Equal(76,allObservations.Count);
}
Deserializing JSON with Newtonsoft, using a specific class
Copy your JSON. Open Visual studio. Create new C# class file. Now Select below menu option:
Edit > Paste Special > Paste JSON as classes
This will create a class as below
public class Rootobject
{
public Datum[] data { get; set; }
}
public class Datum
{
public string type { get; set; }
public string id { get; set; }
}
Now change RootObject
to jsonTask
and deserialise as below
jsonTask test = JsonConvert.DeserializeObject<jsonTask>(strJSON);
Why does Newtonsoft JsonConvert not deserialize Json array fields?
The reason why you could not deserialize it directly is because your json and your data model has a mismatch.
"details":"[{\"field_id\":\"1142488407\",\"response\":\"256\",\"field_type\":\"text\"},..]"
- In this case your
details
data type is string - So, you can NOT parse it directly as a collection of objects
if your json would look like this:
"details":[{\"field_id\":\"1142488407\",\"response\":\"256\",\"field_type\":\"text\"},..]
- the the data type of the
details
field would be a collection
So, the very reason why did your second approach worked is because you have first deserialized the details
then you deserialized the json array.
Deserialize JSON to different Object Types based on JSON content in C#
string JsonMessageFromDevice = "{"device_id":"DeviceTest","message_id":0,"port":3,"portValue":false,"time":"2021-08-25 10:18:51","response_status":"Send"}";
var oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(JsonMessageFromDevice);
or
var jobject = JObject.Parse(JsonMessageFromDevice);
var result = jobject["port"];
if (result != null)
{
ReadResponseMessage readResponseMessage = jobject.ToObject<ReadResponseMessage>();
}
else
{
EventMessage eventMessage = jobject.ToObject<EventMessage>();
}
OR Change model
class ReadResponseMessage {
[JsonProperty("device_id")]
public string DeviceID {get; set;}
[JsonProperty("message_id")]
public int MessageID {get; set;}
[JsonProperty("port")]
public Dictionary<String,bool> Port{get; set;} // or List<string> port
[JsonProperty("time")]
public DateTime Time {get; set;}
[JsonProperty("response_status")]
public string ResponseStatus{get; set;}
}
Deserialize JSON Date to C# Object with DateTime Returning 01/01/0001
Add [JsonProperty("Start Date")]
above public DateTime StartDate { get; set; }
and similar above public DateTime EndDate { get; set; }
:
public class MyObject
{
public string Name { get; set; }
[JsonProperty("Start Date")]
public DateTime StartDate { get; set; }
[JsonProperty("End Date")]
public DateTime EndDate { get; set; }
}
The problem was that json property names ('Start Date') and class property names ('StartDate') were not the same so it defaulted to 01/01/0001.
This will work without the need for IsoDateTimeConverter
.
Related Topics
Passing Variable Between Winforms
How to Run a Simple Bit of Code in a New Thread
How to Get the Client's Ip Address in ASP.NET MVC
What Is the Purpose of the VShost.Exe File
Validateantiforgerytoken Purpose, Explanation and Example
How to Make Databinding Type Safe and Support Refactoring
Using Side-By-Side Assemblies to Load the X64 or X32 Version of a Dll
How to Check If Wpf Is Currently Executing in Design Mode or Not
Using Multiple Versions of the Same Dll
ASP.NET File Download from Server
Open File with Associated Application
How the Int.Tryparse Actually Works
Check Whether Internet Connection Is Available with C#
What Use Is the Aliases Property of Assembly References in Visual Studio 8