I'm trying to deserialize a dynamic JSON (from API) to the correct objects, however some items do not have a type. In the example JSON, the "fulfillment" property has the values "F1" and "F2" and could have more (problem one). Within them, item properties have products order information, but do not have an item type, starting with the product name (ie "03.64.0005_11_10") that can be thousands of options (problem two).
How do I deserialise this JSON to fill in the correct objects? I tried RestCharp, Json.net, but I always get stuck on products property that I can not read and fill dynamically.
I tried the answers below, but no success:
How I deserialize a dynamic json property with RestSharp in C#?
Deserialize JSON into C# dynamic object?
Can you help me please?
"billingAddress": {
"zip": "64001340",
"state": "PI",
"number": "3443",
"status": "ACTIVE",
"firstName": "Fulano",
"telephone": {
"type": "billing",
"number": "88112244"
},
"neighbourhood": "Centro"
},
"clientId": "cliente3",
"documents": [
{
"type": "cpf",
"number": "12345678901"
}
],
"fulfillments": {
"F1": {
"id": "F1",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "708",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "CANCELED",
"type": "SHIPMENT",
"enablePrePicking": false,
"items": {
"03.64.0005_11_10": {
"sku": "03.64.0005_11_10",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.06.0220_48_2": {
"sku": "18.06.0220_48_2",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
},
"F2": {
"id": "F2",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "003",
"operator": {
"id": "5188",
"name": "Loja da Vila"
},
"ownership": "oms",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "SHIPPING_READY",
"type": "SHIPMENT",
"enablePrePicking": true,
"items": {
"18.04.1465_01_3": {
"sku": "18.04.1465_01_3",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.16.0630_13_10": {
"sku": "18.16.0630_13_10",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
}
},
"createdAt": "2019-06-08T21:41:12.000Z",
"updatedAt": "2019-06-08T21:41:12.000Z"
}
To
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public List<Item> items { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
If the problem is just that the keys are dynamic but the structure of those dynamically-keyed objects are well-defined, then you can use a Dictionary<string, T> (instead of a List<T>) to handle the dynamic keys. From your sample JSON it looks like this is the case. So you would need a dictionary for the fulfillments at the root level and the items within the fulfillments. Your classes should look like this:
public class RootObject
{
public BillingAddress billingAddress { get; set; }
public string clientId { get; set; }
public List<Document> documents { get; set; }
public Dictionary<string, Fulfillment> fulfillments { get; set; }
public DateTime createdAt { get; set; }
public DateTime updatedAt { get; set; }
}
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Telephone
{
public string type { get; set; }
public string number { get; set; }
}
public class Document
{
public string type { get; set; }
public string number { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Operator #operator { get; set; }
public string ownership { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public Dictionary<string, Item> items { get; set; }
}
public class Operator
{
public string id { get; set; }
public string name { get; set; }
}
public class Shipment
{
public string method { get; set; }
public string carrierName { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
Then deserialize the JSON into the RootObject class:
var root = JsonConvert.DeserializeObject<RootObject>(json);
Here is a working demo: https://dotnetfiddle.net/xReEQh
Yea that structure really isn't meant to work like that with JSON. Looks like the fulfillments property should have been an array of those objects instead of having those numbered properties. Kind of looks like this is being auto-generated from an EDI file or something, even with that most of the good conversion tools are smart enough not to do this.
Option A: See if whoever is generating that file for you can correct their process.
Option B: If that is not possible, make your fulfillments property a Dictionary type where fulfillment is the class you have for that inner fulfillment object. That would then deserialize it "properly" and would give you a dictionary you can reference using the "F1" key up to "FN" but ideally you would create a list or array from your dictionary when using it. Even if order mattered you always have the id field to sort by later.
// Property on you deserialization object
public Dictionary<string, Fullfillment> fulfillmentDictionary {get; set;}
// Creating the list for easier use of the data
List<Fullfillment> fulfillments = fulfillmentDictionary.Values.ToList();
Similar logic would apply to your item lists.
For JSON messages with dynamic keys (i.e. changing from message to message) you should start with decoding into dynamic C# objects. One decoded (most JSON parsers support it) you enumerate every dynamic property, then convert its value into a POCO like Fulfillment, Item, etc (or just continue to work with the dynamic object).
Here is an example that works with your JSON https://dotnetfiddle.net/U5NfzC
Related
I have a JSON API result that I processed thru an online JSON-to-C# structure program to create the class structure. I've used this many times for other projects. The JSON returned everything along with a public class RootObject that references both the status and payload segments of the returned values.
I am using ASP.NET C# library to deserialize the result JSON using JavaScriptSerializer:
var vlist = new JavaScriptSerializer().Deserialize<TestStruct>(result);
My data structure looks like this (it's pretty standard):
public class TestStruct
{
public class Status
{
public int statusCode { get; set; }
public int errorType { get; set; }
public int errorCode { get; set; }
public string errorMessage { get; set; }
}
public class Payload
{
public VehicleStatusRpt vehicleStatusRpt { get; set; }
}
public class VehicleStatusRpt
{
public string statusType { get; set; }
//public ReportDate reportDate { get; set; }
//public VehicleStatus vehicleStatus { get; set; }
}
public class RootObject
{
public Status status { get; set; }
public Payload payload { get; set; }
}
}
The full JSON Result I'm trying to parse using the class structure is:
{
"status": {
"statusCode": 0,
"errorType": 0,
"errorCode": 0,
"errorMessage": "Success with response body"
},
"payload": {
"vehicleSummary": [
{
"vin": "KNDJX3AE8E7000080",
"vehicleIdentifier": "000080",
"modelName": "SOUL EV",
"modelYear": "2015",
"nickName": "My SOUL",
"generation": 1,
"extColorCode": "1D",
"trim": "EV",
"imagePath": {
"imageName": "2015-soul_ev-ev-1d.png",
"imagePath": "/content/dam/kia/us/owners/image/vehicle/2015/soul_ev/ev/",
"imageType": "1",
"imageSize": {
"length": "100",
"width": "100",
"uom": 0
}
},
"enrollmentStatus": 1,
"fatcAvailable": 1,
"telematicsUnit": 1,
"fuelType": 4,
"colorName": "CLEAR WHITE",
"activationType": 1,
"mileage": "24410",
"dealerCode": "MOBISDLR1",
"mobileStore": [
{
"osType": 0,
"downloadURL": "https://itunes.apple.com/us/app/kia-access-with-uvo-link/id1280548773?mt=8",
"image": {
"imageName": "iosImage.png",
"imagePath": "/content/dam/kia/us/owners/image/common/app/",
"imageType": "2",
"imageSize": {
"length": "100",
"width": "100",
"uom": 0
}
}
},
{
"osType": 1,
"downloadURL": "https://play.google.com/store/apps/details?id=com.myuvo.link",
"image": {
"imageName": "androidImage.png",
"imagePath": "/content/dam/kia/us/owners/image/common/app/",
"imageType": "2",
"imageSize": {
"length": "100",
"width": "100",
"uom": 0
}
}
}
],
"supportedApp": {
"appType": "5",
"appImage": {
"imageName": "app-access.png",
"imagePath": "/content/dam/kia/us/owners/image/common/app/access/",
"imageType": "2",
"imageSize": {
"length": "100",
"width": "100",
"uom": 0
}
}
},
"supportAdditionalDriver": 0,
"customerType": 0,
"vehicleKey": "937db044-8328-4188-a3d2-68ac3b183752"
}
]
}
}
I run this thru json2csharp.com to get the structure (the sample above is an abbreviated 'test' only
The deserializer returns an error: Invalid JSON Primitive (starting with Payload)
I see examples of using RootObject but with the Newtonsoft JSON libary. I would like to use the Microsoft library. Do I really need to switch to Newtonsoft JSON? If I can use JavaScriptSerializer library, how?
The classes that correspond to the JSON you posted are:
public class RootObject
{
public Status status { get; set; }
public Payload payload { get; set; }
}
public class Status
{
public int statusCode { get; set; }
public int errorType { get; set; }
public int errorCode { get; set; }
public string errorMessage { get; set; }
}
public class Payload
{
public List<VehicleSummary> vehicleSummary { get; set; }
}
public class VehicleSummary
{
public string vin { get; set; }
public string vehicleIdentifier { get; set; }
public string modelName { get; set; }
public string modelYear { get; set; }
public string nickName { get; set; }
public int generation { get; set; }
public string extColorCode { get; set; }
public string trim { get; set; }
public Image imagePath { get; set; }
public int enrollmentStatus { get; set; }
public int fatcAvailable { get; set; }
public int telematicsUnit { get; set; }
public int fuelType { get; set; }
public string colorName { get; set; }
public int activationType { get; set; }
public string mileage { get; set; }
public string dealerCode { get; set; }
public List<MobileStore> mobileStore { get; set; }
public SupportedApp supportedApp { get; set; }
public int supportAdditionalDriver { get; set; }
public int customerType { get; set; }
public string vehicleKey { get; set; }
}
public class Image
{
public string imageName { get; set; }
public string imagePath { get; set; }
public string imageType { get; set; }
public ImageSize imageSize { get; set; }
}
public class ImageSize
{
public string length { get; set; }
public string width { get; set; }
public int uom { get; set; }
}
public class MobileStore
{
public int osType { get; set; }
public string downloadURL { get; set; }
public Image image { get; set; }
}
public class SupportedApp
{
public string appType { get; set; }
public Image appImage { get; set; }
}
I was able to deserialize the JSON just fine using JavaScriptSerializer like this:
var root = new JavaScriptSerializer().Deserialize<RootObject>(result);
where result is the JSON string you posted in your question.
Note, however, that if you have placed your classes inside another class called TestStruct then you would need to take that into account and deserialize to TestStruct.RootObject instead, e.g.:
var root = new JavaScriptSerializer().Deserialize<TestStruct.RootObject>(result);
I was also able to deserialize the JSON using Json.Net in the same way with the JsonConvert class:
var root = JsonConvert.DeserializeObject<RootObject>(result);
Once you have the deserialized object, you can extract some interesting information from it like this:
foreach (var vs in root.payload.vehicleSummary)
{
Console.WriteLine(string.Format("{0} - {1} {2} {3}, {4} mi",
vs.vin, vs.colorName, vs.modelYear, vs.modelName, vs.mileage));
}
Here is a working demo using Json.Net: https://dotnetfiddle.net/Zh35be
I have a JSON object with a dynamic key for the properties I wish to map to a class. I'm uncertain how to build my class to deserialize with JSON.NET. I need the values from the 'results' and 'more' keys at the upper level and also the the values from the 'timesheets' key.
Here is my JSON data.
{
"results": {
"timesheets": {
"7994790": {
"id": 7994790,
"user_id": 165502,
"jobcode_id": 11267673,
"start": "2019-12-20T05:48:00-05:00",
"end": "2019-12-20T13:44:00-05:00",
"duration": 28560,
"date": "2019-12-20",
"tz": -5,
"tz_str": "tsET",
"type": "regular",
"location": "Android App",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"20251": "",
"19647": "Laborer",
"20327": "",
"19648": ""
},
"last_modified": "2019-12-20T20:28:48+00:00",
"attached_files": [],
"created_by_user_id": 165502
},
"8087496": {
"id": 8087496,
"user_id": 165502,
"jobcode_id": 2415904,
"start": "2019-12-20T13:44:00-05:00",
"end": "2019-12-20T15:11:00-05:00",
"duration": 5220,
"date": "2019-12-20",
"tz": -5,
"tz_str": "tsET",
"type": "regular",
"location": "Android App",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"20251": "",
"19647": "Laborer",
"20327": "",
"19648": ""
},
"last_modified": "2019-12-20T20:28:49+00:00",
"attached_files": [],
"created_by_user_id": 165502
}
}
},
"more": false
}
And my classes as I currently have them which returns this error.
System.ArgumentNullException: 'Value cannot be null.
Parameter name: values'
public class RootObject
{
public Results results { get; set; }
public bool more { get; set; }
}
public class Results
{
public Timesheets timesheets { get; set; }
}
public class Timesheets
{
public Dictionary<int, TimesheetDetails> timesheetsdetails { get; set; }
}
public class TimesheetDetails
{
public int id { get; set; }
public int user_id { get; set; }
public int jobcode_id { get; set; }
public DateTime start { get; set; }
public DateTime end { get; set; }
public int duration { get; set; }
public string date { get; set; }
public int tz { get; set; }
public string tz_str { get; set; }
public string type { get; set; }
public string location { get; set; }
public bool on_the_clock { get; set; }
public int locked { get; set; }
public string notes { get; set; }
public DateTime last_modified { get; set; }
public List<object> attached_files { get; set; }
public int created_by_user_id { get; set; }
}
var stuff = JsonConvert.DeserializeObject<RootObject>(result.Content);
Console.WriteLine(string.Join(",", stuff.results.timesheets.timesheetsdetails));
First of all your json is not valid. After the end of the first timesheet data, there should be a , You can use any json validator online simply to validate it.
And in your model the Results is not valid according to the json. The below one works for me.
public class Response
{
[JsonProperty("results")] public TimeSheetResponse TimeSheetResponse { get; set; }
[JsonProperty("more")] public bool More { get; set; }
}
public class TimeSheetResponse
{
[JsonProperty("timesheets")] public Dictionary<string, Timesheet> Timesheets { get; set; }
}
public class Timesheet
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("user_id")]
public long UserId { get; set; }
[JsonProperty("jobcode_id")]
public long JobcodeId { get; set; }
[JsonProperty("start")] public DateTimeOffset Start { get; set; }
[JsonProperty("end")] public DateTimeOffset End { get; set; }
[JsonProperty("duration")] public long Duration { get; set; }
[JsonProperty("date")] public DateTimeOffset Date { get; set; }
[JsonProperty("tz")] public long Tz { get; set; }
[JsonProperty("tz_str")] public string TzStr { get; set; }
[JsonProperty("type")] public string Type { get; set; }
[JsonProperty("location")] public string Location { get; set; }
[JsonProperty("on_the_clock")] public bool OnTheClock { get; set; }
[JsonProperty("locked")] public long Locked { get; set; }
[JsonProperty("notes")] public string Notes { get; set; }
[JsonProperty("customfields")] public Dictionary<string, string> Customfields { get; set; }
[JsonProperty("last_modified")] public DateTimeOffset LastModified { get; set; }
[JsonProperty("attached_files")] public List<object> AttachedFiles { get; set; }
[JsonProperty("created_by_user_id")]
public long CreatedByUserId { get; set; }
}
To deserialize to Object..
var timeSheetResult = JsonConvert.DeserializeObject<Response>(data);
In my c# project, I would like to access specific information (POI name and distance) inside a complex and nested JSON.
This JSON is the result of an Azure Maps API call.
I have tried to deserialise it into an object. But this JSON is too complex and I am unable to do it.
What is the best way to extract the information I need ?
{
"summary": {
"query": "university",
"queryType": "NON_NEAR",
"queryTime": 103,
"numResults": 1,
"offset": 0,
"totalResults": 216684,
"fuzzyLevel": 1,
"geoBias": {
"lat": 48.008446,
"lon": 7.821583
}
},
"results": [
{
"type": "POI",
"id": "DE/POI/p0/1505647",
"score": 2.574,
"dist": 774.6544330765787,
"info": "search:ta:276009006412786-DE",
"poi": {
"name": "Universität Freiburg Medizinische Fakultät",
"phone": "+(49)-(761)-27072350",
"url": "www.med.uni-freiburg.de",
"categories": [
"college/university"
],
"classifications": [
{
"code": "COLLEGE_UNIVERSITY",
"names": [
{
"nameLocale": "en-US",
"name": "college/university"
}
]
}
]
},
"address": {
"streetName": "Elsässer Straße",
"municipalitySubdivision": "Mooswald",
"municipality": "Freiburg im Breisgau",
"countrySecondarySubdivision": "Freiburg im Breisgau",
"countrySubdivision": "Baden-Württemberg",
"postalCode": "79110",
"countryCode": "DE",
"country": "Germany",
"countryCodeISO3": "DEU",
"freeformAddress": "Elsässer Straße, 79110 Freiburg Im Breisgau"
},
"position": {
"lat": 48.00894,
"lon": 7.83197
},
"viewport": {
"topLeftPoint": {
"lat": 48.00984,
"lon": 7.83063
},
"btmRightPoint": {
"lat": 48.00804,
"lon": 7.83331
}
},
"entryPoints": [
{
"type": "main",
"position": {
"lat": 48.00931,
"lon": 7.83259
}
}
]
}
]
}
Step 1:
Parse your JSON in a JSON parser website such as https://jsonparser.org
This will help you understand the content and how it will be translated as an object.
For example, your JSON string gives this result :
Step2:
Open the query tool of this website, this will help you find out the object path to the information you need.
For example, for your JSON string, to access the POI name :
Step 3:
In your Visual Studio project, install the NuGet package: Newtonsoft.Json and Microsoft.CSharp in your shared library.
If you are processing the JSON in a separate library, please also install the Newtonsoft.Json NuGet package in the main project.
Step 4:
If JSONstring is your JSON string :
using Newtonsoft.Json;
dynamic NewObject = JsonConvert.DeserializeObject<dynamic>(JSONstring);
string Name = NewObject.results[0].poi.name;
string Distance = NewObject.results[0].dist;
You have at least 2 solutions possible:
Either you create classes that mirror the content of the json you are expecting
public class MyJSON
{
public Summary summary { get; set; }
public List<Result> results { get; set; }
...
}
public class Summary
{
public string query { get; set; }
...
}
Then you could deserialize using Newtonsoft.Json
JsonConvert.DeserializeObject<MyJSON>(jsonstring);
Or you could directly deserialize to a dynamic object and access the properties directly by name.
dynamic data = JsonConvert.DeserializeObject<dynamic>(jsonstring);
string query = data[0].summary.query;
Solution 1 requires you to create the classes first, but is faster and more secure to access (less prone to wrong naming, or data structure changes)
Solution 2 is much more volatile and flexible, you just access what you need. But you could get exceptions if you try to access properties that do not exist in the json object.
i converted your json via json2csharp
then you can use Newtonsoft to deserialize them
RootObject root= JsonConvert.DeserializeObject(JSONstring)
public class GeoBias
{
public double lat { get; set; }
public double lon { get; set; }
}
public class Summary
{
public string query { get; set; }
public string queryType { get; set; }
public int queryTime { get; set; }
public int numResults { get; set; }
public int offset { get; set; }
public int totalResults { get; set; }
public int fuzzyLevel { get; set; }
public GeoBias geoBias { get; set; }
}
public class Name
{
public string nameLocale { get; set; }
public string name { get; set; }
}
public class Classification
{
public string code { get; set; }
public List<Name> names { get; set; }
}
public class Poi
{
public string name { get; set; }
public string phone { get; set; }
public string url { get; set; }
public List<string> categories { get; set; }
public List<Classification> classifications { get; set; }
}
public class Address
{
public string streetName { get; set; }
public string municipalitySubdivision { get; set; }
public string municipality { get; set; }
public string countrySecondarySubdivision { get; set; }
public string countrySubdivision { get; set; }
public string postalCode { get; set; }
public string countryCode { get; set; }
public string country { get; set; }
public string countryCodeISO3 { get; set; }
public string freeformAddress { get; set; }
}
public class Position
{
public double lat { get; set; }
public double lon { get; set; }
}
public class TopLeftPoint
{
public double lat { get; set; }
public double lon { get; set; }
}
public class BtmRightPoint
{
public double lat { get; set; }
public double lon { get; set; }
}
public class Viewport
{
public TopLeftPoint topLeftPoint { get; set; }
public BtmRightPoint btmRightPoint { get; set; }
}
public class Position2
{
public double lat { get; set; }
public double lon { get; set; }
}
public class EntryPoint
{
public string type { get; set; }
public Position2 position { get; set; }
}
public class Result
{
public string type { get; set; }
public string id { get; set; }
public double score { get; set; }
public double dist { get; set; }
public string info { get; set; }
public Poi poi { get; set; }
public Address address { get; set; }
public Position position { get; set; }
public Viewport viewport { get; set; }
public List<EntryPoint> entryPoints { get; set; }
}
public class RootObject
{
public Summary summary { get; set; }
public List<Result> results { get; set; }
}
I'm a little confused on the best way to parse the following JSON structure.
{
"featured": {
"id": 15,
"title": "media 1 -> 7",
"description": "test1",
"short_description": "test1",
"rating_avg": 0.0,
"image": "//d25xdrj7gd7wz1.cloudfront.net/covers/1603/1452024324.jpg"
},
"categories": [
{
"id": 1,
"title": "category 0",
"description": null,
"position": 0,
"media": [
{
"id": 1,
"title": "media 0 -> 0",
"description": "test1",
"short_description": "test1",
"rating_avg": 0.0,
"image": "//d25xdrj7gd7wz1.cloudfront.net/covers/1603/1452024324.jpg",
"category_media": {
"position": 0,
"category_id": 1,
"media_id": 1,
"id": 1
}
}, ...
Basically I have an array of categories which contains an array of medias (the featured is for something else)
I am looking to return List and the Category object contains a List
and I created some models:
public class Category
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public List<Media> MediaList { get; set; }
}
public class Media
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string ShortDescription { get; set; }
public string Image { get; set; }
}
..and I am supposed to use Newtonsoft?
I looked at the following example: Deserializing Partial JSON Fragments but I would think I don't need to convert from JToken -> Category ... etc. In other words, I would think it would be easy to just return my List.
I'm new to LINQ (I come from a python background) so I'm getting to know C#
Use This as your Model
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class JsonModel
{
[JsonProperty("featured")]
public Featured Featured { get; set; }
[JsonProperty("categories")]
public List<Category> Categories { get; set; }
}
public partial class Category
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("description")]
public object Description { get; set; }
[JsonProperty("position")]
public long Position { get; set; }
[JsonProperty("media")]
public List<Featured> Media { get; set; }
}
public partial class Featured
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("short_description")]
public string ShortDescription { get; set; }
[JsonProperty("rating_avg")]
public long RatingAvg { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("category_media", NullValueHandling = NullValueHandling.Ignore)]
public CategoryMedia CategoryMedia { get; set; }
}
public partial class CategoryMedia
{
[JsonProperty("position")]
public long Position { get; set; }
[JsonProperty("category_id")]
public long CategoryId { get; set; }
[JsonProperty("media_id")]
public long MediaId { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
}
}
Then do this in your Class:
var info = JsonConvert.DeserializeObject<JsonModel>(json);
var featured = info.Featured;
var categories = info.Categories;
You don't need LINQ in this case unless you want to change the data structure. To parse json file to list you have to create a class that matches a structure of your file, like:
class DataModel
{
public Featured Featured { get; set; }
public List<Category> Categories { get;set; }
}
Also, please pay attention that you need to use attribute [JsonProperty(PropertyName="fieldName")] if property name in json is different from property name in class.
And finally, to parse the data use the following row:
var data = JsonConvert.DeserializeObject<DataModel>(jsonString);
Act as follow:
Update your models with:
public class Category
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public List<Media> Media { get; set; }
}
public class Media
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string ShortDescription { get; set; }
public string Image { get; set; }
}
public class Featured
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Short_Description { get; set; }
}
And then make a model same as your JSON structure:
public class YOUR_MODEL
{
public Featured Featured { get; set; }
public List<Category> Categories { get;set; }
}
And then Descrilize your JSON to your object:
YOUR_MODELresults = JsonConvert.DeserializeObject<YOUR_MODEL>(YOUR_JSON);
To get your model you can use tool like :
https://jsonutils.com/ or http://json2csharp.com/
In case of need you can also validate json syntax with : https://jsonlint.com/ to get detailed errors.
With a slightly modified version of your example, I get :
public class CategoryMedia
{
public int position { get; set; }
public int category_id { get; set; }
public int media_id { get; set; }
public int id { get; set; }
}
public class Medium
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
public string short_description { get; set; }
public double rating_avg { get; set; }
public string image { get; set; }
public CategoryMedia category_media { get; set; }
}
public class Category
{
public int id { get; set; }
public string title { get; set; }
public object description { get; set; }
public int position { get; set; }
public IList<Medium> media { get; set; }
}
public class Featured
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
public string short_description { get; set; }
public double rating_avg { get; set; }
public string image { get; set; }
public IList<Category> categories { get; set; }
}
public class Example
{
public Featured featured { get; set; }
}
It spares a lot of time for creating models and it allows you to verify that you don't have typos in field names.
With this, you just have to deserialize your JSON sample to "Example" class, using the library of your choice. Newtonsoft Json is a very efficient classical !
Newtonsoft is the standard for doing work like this. So lets look at the best way to do this. First lets start with your json format and fix it so you can use the online tools available to create a good model structure:
[
{
"featured": {
"id": 15,
"title": "media 1 -> 7",
"description": "test1",
"short_description": "test1",
"rating_avg": 0.0,
"image": "//d25xdrj7gd7wz1.cloudfront.net/covers/1603/1452024324.jpg"
},
"categories": [
{
"id": 1,
"title": "category 0",
"description": null,
"position": 0,
"media": [
{
"id": 1,
"title": "media 0 -> 0",
"description": "test1",
"short_description": "test1",
"rating_avg": 0.0,
"image": "//d25xdrj7gd7wz1.cloudfront.net/covers/1603/1452024324.jpg",
"category_media": {
"position": 0,
"category_id": 1,
"media_id": 1,
"id": 1
}
}
]
}
]
}
]
Now if you plug that into http://json2csharp.com/, it will output a good model structure:
public class Featured
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
public string short_description { get; set; }
public double rating_avg { get; set; }
public string image { get; set; }
}
public class CategoryMedia
{
public int position { get; set; }
public int category_id { get; set; }
public int media_id { get; set; }
public int id { get; set; }
}
public class Medium
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
public string short_description { get; set; }
public double rating_avg { get; set; }
public string image { get; set; }
public CategoryMedia category_media { get; set; }
}
public class Category
{
public int id { get; set; }
public string title { get; set; }
public object description { get; set; }
public int position { get; set; }
public List<Medium> media { get; set; }
}
public class RootObject
{
public Featured featured { get; set; }
public List<Category> categories { get; set; }
}
Feel free to rename RootObject So now lets look are how you can deserialize your json into your model objects using Newtonsoft:
Firstly you need to get your json file into a string format, so lets say its a file on your computer or in your project, there is many ways to retrieve it, either using Assembly, or Directory methods. Once you have access to your json file, read out the contents and then using Newtonsoft method for deserialising:
var myString = File.ReadAllText(path)
var myObject = JsonConvert.DeserializeObject<RootObject>(myString);
And thats it:P
I`m trying to build web api for complex object. For this aim I built the custom binder which deserialize this object from JSON.
My Customer Binder looks like:
var paramType = p_BindingContext.ModelType;
dynamic updatedParam = Activator.CreateInstance(paramType);
JsonReader reader = new JTokenReader(JObject.Parse
(p_ActionContext.Request.Content.ReadAsStringAsync().Result));
JObject jObject = JObject.Load(reader);
JsonSerializer serializer = new JsonSerializer();
serializer.Populate(jObject.CreateReader(), updatedParam);//Here the exception thorws
p_BindingContext.Model = updatedParam;
The object to serialize is very comlex:
public class ModelRegisterUserRequest{
public ModelUser User { get; set; }
public CampaignItem CampaignWithChosenProposal { get; set; }
public string ValidationToken { get; set; }
public string IVRToken { get; set; }
public string DealerID { get; set; }
public string SalePersonID { get; set; }
}
public class CampaignItem
{
public List<BannerItem> Banners { get; set; }
public string Code { get; set; }
public string CustomerInstruction { get; set; }
public string InfoLink { get; set; }
public string LobbySubTitle { get; set; }
public string LobbyTitle { get; set; }
public string MoreText { get; set; }
public uint NumOfColumns { get; set; }
public uint NumOfRows { get; set; }
public string OriginString { get; set; }
public int OriginInt { get; set; }
public List<ProposalItem> Proposals { get; set; }
public string RegulationsInfoLink { get; set; }
public string ServiceType { get; set; }
public string SubTitle { get; set; }
public string SWDefault { get; set; }
public string Title { get; set; }
}
public partial class ProposalItem
{
public List<string> EquipmentsCode { get; set; }
public string FeatureCode { get; set; }
public string InvalidReason { get; set; }
public bool IsExistsMoreInfo { get; set; }
public bool IsValid { get; set; }
public string LeadCode { get; set; }
public int ParamCombinationCode { get; set; }
public string ProductCode { get; set; }
public string ProductCombinationCode { get; set; }
public string ProposalCode { get; set; }
public List<ColumnItem> Columns { get; set; }
public List<MoreInfoItem> MoreInfoList { get; set; }
public List<string> PricePlans { get; set; }
public string ProductName { get; set; }
}
The Json is created with JSON.stringify command from Javascript code and look like :
{
"ValidationToken": "1cc6cca8-44d5-4042-af37-de6a0d198d17",
"AppID": "TST",
"campaignWithChosenProposal": {
"Banners": [
{
"LocationCodeString": "ManagerTab",
"LocationCodeInt": 256,
"MediaUrl": "BANNER 10"
}
],
"Code": "CAMP221",
"CustomerInstruction": "-1",
"InfoLink": "http://test.aspx",
"LobbySubTitle": "",
"LobbyTitle": "",
"MoreText": "",
"NumOfColumns": 0,
"NumOfRows": 0,
"OriginString": "INT",
"OriginInt": 4,
"Proposals": [
[
{
"EquipmentsCode": [
"5455"
],
"FeatureCode": "BE5455",
"InvalidReason": "",
"IsExistsMoreInfo": true,
"IsValid": true,
"LeadCode": "3792956510",
"ParamCombinationCode": 0,
"ProductCode": "OANTIVRP2",
"ProductCombinationCode": "0",
"ProposalCode": "291600010201C8F83661D5B82FD5F3603967588B7A72",
"Columns": [
{
"Content": ""
},
{
"Content": ""
},
{
"Content": ""
},
{
"Content": ""
},
{
"Content": ""
},
{
"Content": ""
}
],
"MoreInfoList": [
{
"Content": "3",
"MoreInfoTypesString": "LicenseFrom",
"MoreInfoTypesInt": 16
},
{
"Content": "3",
"MoreInfoTypesString": "LicenseTo",
"MoreInfoTypesInt": 32
},
{
"Content": "4.3",
"MoreInfoTypesString": "PricePeriod1",
"MoreInfoTypesInt": 64
}
],
"PricePlans": [
"O2"
],
"ProductName": ""
}
]
],
"RegulationsInfoLink": "http://www.test.aspx",
"ServiceType": "TST",
"SubTitle": "",
"SWDefault": "1",
"Title": ""
},
"User": {
"CurrentLicenseNumber": 0,
"CustomerID": "21670106",
"FirstName": "",
"LastName": "",
"RequestedLicenseNumber": "3",
"SubscriberPhoneNumber": "035448428",
"IdentityNumber": "058470",
"Email": "alexanrbe#gmail.com",
"RegistrationStatus": "NOTREGISTERED"
},
"SalePersonID": "3178364",
}
The Exception is thrown on serilization row and looks like:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type WebAPI.Models.Entities.Campaigns.CampaignObjects.ProposalItem' 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<T> 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.
I spent nights for resolve this exception but did not find any solutions
Also the solutions on this site are excisted but not supports such complex problem.
https://stackoverflow.com/questions/11126242/using-jsonconvert-deserializeobject-to-deserialize-json-to-a-c-sharp-poco-class
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
Somebody met such JSON unexpected behaiviour and could help?
Thanks
According to your JSON data, the objects that you need to map to have to look like this (unless you have your own JsonDeserializer of course):
public class Banner
{
public string LocationCodeString { get; set; }
public int LocationCodeInt { get; set; }
public string MediaUrl { get; set; }
}
public class CampaignWithChosenProposal
{
public List<Banner> Banners { get; set; }
public string Code { get; set; }
public string CustomerInstruction { get; set; }
public string InfoLink { get; set; }
public string LobbySubTitle { get; set; }
public string LobbyTitle { get; set; }
public string MoreText { get; set; }
public int NumOfColumns { get; set; }
public int NumOfRows { get; set; }
public string OriginString { get; set; }
public int OriginInt { get; set; }
public List<List<>> Proposals { get; set; }
public string RegulationsInfoLink { get; set; }
public string ServiceType { get; set; }
public string SubTitle { get; set; }
public string SWDefault { get; set; }
public string Title { get; set; }
}
public class User
{
public int CurrentLicenseNumber { get; set; }
public string CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string RequestedLicenseNumber { get; set; }
public string SubscriberPhoneNumber { get; set; }
public string IdentityNumber { get; set; }
public string Email { get; set; }
public string RegistrationStatus { get; set; }
}
public class RootObject
{
public string ValidationToken { get; set; }
public string AppID { get; set; }
public CampaignWithChosenProposal campaignWithChosenProposal { get; set; }
public User User { get; set; }
public string SalePersonID { get; set; }
}
Here is a really cool tool (json2csharp) to help you out.