How to Deserialize the following Json string in C#? - c#

I'm trying to deserialize the following JSON:
{
"runtimeOptions": {
"tfm": "net6.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "6.0.0"
}
],
"configProperties": {
"MaxTargets" : "1024"
}
}
}
My model class looks like:
public class OptionalInclude
{
[JsonProperty("configProperties")]
public string ConfigProperties { get; set; }
[JsonProperty("tfm")]
public string Tfm { get; set; }
[JsonProperty("frameworks")]
public IList<Dictionary<string, string>> Frameworks { get; set; }
}
I'm trying to deserialize in this way, but I need the MaxTargets value from the JSON:
var optionalIncludesConfig = File.ReadAllText(configPath);
result = (JObject)JsonConvert.DeserializeObject(optionalIncludesConfig);
var optionIncludes = new List<OptionalInclude>();
optionIncludes = result.ToObject<List<OptionalInclude>>();

configProperties in your JSON is really a object, and you are forgetting about your top level object runtimeOptions. You should change your model to be:
public class TopLevel //this should be something more descriptive - only used as an example
{
[JsonProperty("runtimeOptions")]
public RuntimeOptions runtimeOptions { get; set; }
}
public class RuntimeOptions
{
[JsonProperty("configProperties")]
public ConfigProperties ConfigProperties { get; set; }
[JsonProperty("tfm")]
public string Tfm { get; set; }
[JsonProperty("frameworks")]
public IList<Dictionary<string, string>> Frameworks { get; set; }
}
public class ConfigProperties
{
[JsonProperty("maxTargets")]
public string MaxTargets { get; set; }
}
Then to deserialize, you should be able to deserialize into an TopLevel object and retrieve configProperties to get your MaxTargets:
var optionalIncludesConfig = File.ReadAllText(configPath);
var result = JsonConvert.DeserializeObject<TopLevel>(optionalIncludesConfig);
string maxTargets = result.runtimeOptions.ConfigProperties.MaxTargets;
It should look something like this as seen in this HttpPost example (where the post body is the JSON found in your question):

Firstly, the ConfigProperties property on OptionalInclude is not a string type in the JSON, it is an object, so you should hard-type it like this:
public class ConfigProperties
{
[JsonProperty("MaxTargets")]
public string MaxTargets { get; set; }
}
Secondly, I think the frameworks in your JSON would make more sense to have a Framework class like this:
public class Framework
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
}
and use an List<Framework> instead. Lastly, you either need a class like this:
public class SomeClassName
{
[JsonProperty("runtimeOptions")]
public OptionalInclude RuntimeOptions { get; set; }
}
and then deserialize into that, or you need to parse the JSON into a JObject, navigate it into the first layer of the object (the "runtimeOptions" object) and then parse that value into OptionalInclude (I'd just hard-type it, personally).
Your resulting OptionalInclude class should end up like this:
public class OptionalInclude
{
[JsonProperty("configProperties")]
public ConfigProperties ConfigProperties { get; set; }
[JsonProperty("tfm")]
public string Tfm { get; set; }
[JsonProperty("frameworks")]
public List<Framework> Frameworks { get; set; }
}
Then you should be able to deserialize it like this:
var jsonString = File.ReadAllText(configPath);
var result = JsonConvert.DeserializeObject<SomeClassName>(jsonString);
Note specifically that you can DeserializeObject and use a specific object type instead of casting to a JObject.
Here is a .NET Fiddle of the full code.

Approach 1
You can access attributes of a JObject with the [ ] operator, for example assuming json is a JObject containing the json you provided:
var maxTargets = json["runtimeOptions"]["configProperties"]["MaxTargets"].ToString();
I find this approach fast, but it's easy to mess up with null tokens and such. Also, this isn't a very polished soluton.
Approach 2
I personally like to have classes for nested jsons, so for example:
public class ConfigProperties {
[JsonProperty("MaxTargets")]
public string MaxTargets { get; set; }
}
and then add it to your outer class:
public class OptionalInclude {
// other stuff
public ConfigProperties Properties { get; set; }
}
then you will be able do deserialize it. However, I see you are using a List of OptionalInclude. Assuming that you are cycling through such list:
foreach (var item in optionalIncludes) {
var maxTargets = item.Properties.MaxTargets;
// your logic
}

configProperties is not an enumerable (list)
You can make:
public class Configuration
{
[JsonProperty("runtimeOptions")]
public RuntimeOptions RuntimeOptions { get; set; }
}
public class RuntimeOptions
{
[JsonProperty("tfm")]
public string Tfm { get; set; }
[JsonProperty("frameworks")]
public List<Framework> Frameworks { get; set; }
[JsonProperty("configProperties")]
public ConfigProperties ConfigProperties { get; set; }
}
public class Framework
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
}
public class ConfigProperties
{
[JsonProperty("MaxTargets")]
public string MaxTargets { get; set; }
}
Then you code:
var configuration = File.ReadAllText(configPath);
var result = JsonSerializer.Deserialize<Configuration>(configuration);
string optionInclude = result.RuntimeOptions.ConfigProperties.MaxTargets;

Related

deserialize API response with different json value in the result

I'm querying an external service and wanted to deserialize the response into a customer object but the issue is response for each customer may be different. some customer may have Sales entity in the response and few may have Marketing.
The json property for sales entity is SalesId and for marketing is MarketingId. Can you advise whether the model I use to store result is correct or any improvement ? If so, how would I deserialize the response without knowing the correct json property ?
For Customer 66666
{
"customerId": "66666",
"customerName": "test1234",
"dependentEntity": [
{
"SalesId": "3433434",
"SalesPersonName": "343434",
"SaleSource": "StorePurchase"
}
]
}
For Customer 5555
{
"customerId": "55555",
"customerName": "test2",
"dependentEntity": [
{
"MarketingId": "3433434",
"MarketingAppName": "343434",
"MarketingSource": "Online"
}
]
}
Here is the Model I'm thinking but not sure the correct one
public class Customer
{
public string customerId { get; set; }
public string customerName { get; set; }
public IList<T> dependentList { get; set; }
}
public class Dependent
{
[JsonProperty("Id")]
public string Id { get; set; }
public string Name { get; set; }
public string Source { get; set; }
}
You could probably try something like the following one:
public class DependentEntity
{
[JsonProperty("SalesId")]
public string SalesId { get; set; }
[JsonProperty("SalesPersonName")]
public string SalesPersonName { get; set; }
[JsonProperty("SaleSource")]
public string SaleSource { get; set; }
[JsonProperty("MarketingId")]
public string MarketingId { get; set; }
[JsonProperty("MarketingAppName")]
public string MarketingAppName { get; set; }
[JsonProperty("MarketingSource")]
public string MarketingSource { get; set; }
}
public class Customer
{
[JsonProperty("customerId")]
public string CustomerId { get; set; }
[JsonProperty("customerName")]
public string CustomerName { get; set; }
[JsonProperty("dependentEntity")]
public IList<DependentEntity> DependentEntity { get; set; }
}
We have a type for DependentEntity that has both the attributes of Marketing and Sales object. After parsing your input, you could create a logic (checking the attributes) based on which you could check if a DependentEntity is a Marketing or a Sales object.
The above classes was generated using, jsonutils.
If we can assume that the dependentEntity contains only a single type of objects then you can use json.net's schema to perform branching based on the matching schema.
So, lets suppose you have these dependent entity definitions:
public class DependentMarket
{
public string MarketingId { get; set; }
public string MarketingAppName { get; set; }
public string MarketingSource { get; set; }
}
public class DependentSales
{
public string SalesId { get; set; }
public string SalesPersonName { get; set; }
[JsonProperty("SaleSource")]
public string SalesSource { get; set; }
}
...
Then you can use these classes to generate json schemas dynamically:
private static JSchema marketSchema;
private static JSchema salesSchema;
//...
var generator = new JSchemaGenerator();
marketSchema = generator.Generate(typeof(DependentMarket));
salesSchema = generator.Generate(typeof(DependentSales));
And finally you can do the branching like this:
var json = "...";
var semiParsedJson = JObject.Parse(json);
JArray dependentEntities = (JArray)semiParsedJson["dependentEntity"];
JObject probeEntity = (JObject)dependentEntities.First();
if (probeEntity.IsValid(marketSchema))
{
var marketEntities = dependentEntities.ToObject<List<DependentMarket>>();
...
}
else if (probeEntity.IsValid(salesSchema))
{
var salesEntities = dependentEntities.ToObject<List<DependentSales>>();
...
}
else if ...
else
{
throw new NotSupportedException("The provided json format is not supported");
}

Deserialize JSON using specific properties

I'm trying to deserialize JSON without declaring every property in C#. Here is a cut-down extract of the JSON:
{
"resourceType": "export",
"type": "search",
"total": 50,
"timestamp": "2020-08-02T18:26:06.747+00:00",
"entry": [
{
"url": "test.com/123",
"resource": {
"resourceType": "Slot",
"id": [
"123"
],
"schedule": {
"reference": {
"value": "testvalue"
}
},
"status": "free",
"start": "2020-08-03T08:30+01:00",
"end": "2020-08-03T09:00+01:00"
}
}
]
}
I want to get the values out of entry → resource, id and start.
Any suggestions on the best way to do this?
I've made very good experiences with json2sharp. You can enter your JSON data there and it will generate the classes you need to deserialize the JSON data for you.
public class Reference
{
public string value { get; set; }
}
public class Schedule
{
public Reference reference { get; set; }
}
public class Resource
{
public string resourceType { get; set; }
public List<string> id { get; set; }
public Schedule schedule { get; set; }
public string status { get; set; }
public string start { get; set; }
public string end { get; set; }
}
public class Entry
{
public string url { get; set; }
public Resource resource { get; set; }
}
public class Root
{
public string resourceType { get; set; }
public string type { get; set; }
public int total { get; set; }
public DateTime timestamp { get; set; }
public List<Entry> entry { get; set; }
}
The next step is to choose a framework which will help you to deserialize. Something like Newtonsoft JSON.
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
If you want to get the data without declaring classes, you can use Json.Net's LINQ-to-JSON API (JToken, JObject, etc.). You can use the SelectToken method with a JsonPath expression to get what you are looking for in a couple of lines. Note that .. is the recursive descent operator.
JObject obj = JObject.Parse(json);
List<string> ids = obj.SelectToken("..resource.id").ToObject<List<string>>();
DateTimeOffset start = obj.SelectToken("..resource.start").ToObject<DateTimeOffset>();
Working demo here: https://dotnetfiddle.net/jhBzl4
If it turns out there are actually multiple entries and you want to get the id and start values for all of them, you can use a query like this:
JObject obj = JObject.Parse(json);
var items = obj["entry"]
.Children<JObject>()
.Select(o => new
{
ids = o.SelectToken("resource.id").ToObject<List<string>>(),
start = o.SelectToken("resource.start").ToObject<DateTimeOffset>()
})
.ToList();
Demo: https://dotnetfiddle.net/Qe8NB7
I am not sure why you don't deserialize the lot (even if it's minimally populated) since you have to do the inner classes anyway.
Here is how you could bypass some of the classes (1) by digging into the JObjects
Given
public class Reference
{
public string value { get; set; }
}
public class Schedule
{
public Reference reference { get; set; }
}
public class Resource
{
public string resourceType { get; set; }
public List<string> id { get; set; }
public Schedule schedule { get; set; }
public string status { get; set; }
public string start { get; set; }
public string end { get; set; }
}
public class Entry
{
public string url { get; set; }
public Resource resource { get; set; }
}
You could call
var results = JObject.Parse(input)["entry"]
.Select(x => x.ToObject<Entry>());

Custom JSON Serialize with custom mapping C#

I want to serialize/deserialize the following JSON:
{
"result": {
"ID": 1,
"TITLE": "Example",
"ARRAY": [
{
"Item1": "Result1",
"Item2": "Result2"
}
]
}
}
I tried with the following class format, but no sucess yet... Can someone help me deserialize it?
public class myClass
{
public string ID { get; set; }
[JsonProperty("TITLE")]
public string Name { get; set; }
}
obs.: Using the namespace Newtonsoft.JSON
In your example class definition above, you have called the class myClass but you would have had to call it result because ID and TITLE are members of the result JSON in the given example. myClass would not resolve to anything.
I don't know why you'd want to have a property called Name that is mapped to TITLE, but ok, if you want to do that you can modify the solution after you get it working.
Still, we're not done yet. You also have a JSON member called ARRAY and you need to define a separate class for that.
And still there is an additional problem: the result JSON is nested inside an implicit base object, so we need to define that as well. Let's call it BaseResult.
public class ARRAY
{
public string Item1 { get; set; }
public string Item2 { get; set; }
}
public class Result
{
public int ID { get; set; }
public string TITLE { get; set; }
public List<ARRAY> ARRAY { get; set; }
}
public class BaseResult
{
public Result result { get; set; }
}
If you are using Visual Studio, you can copy your JSON and paste it in any *.cs file with Edit > Paste Special > Paste JSON as Classes. It will generate POCO objects representing your JSON, which in your case will be this:
public class Rootobject
{
public Result result { get; set; }
}
public class Result
{
public int ID { get; set; }
public string TITLE { get; set; }
public ARRAY[] ARRAY { get; set; }
}
public class ARRAY
{
public string Item1 { get; set; }
public string Item2 { get; set; }
}
Then, asuming that you have your JSON in a string variable named data, you can deserialize it as follows:
var result= JsonConvert.DeserializeObject<Rootobject>(data);

JSon.NET deserialising subitems

For deserialisation I usually use an object with the same property names as found in the JSon and JsonConvert.DeserializeObject<Des>(jsonstring).
But now I came across this:
{
"id": 0815,
"name": "whatever"
"addedInfo": {
"thisisinteresting": 4711,
"id_str": "2336"
}
}
How can I tell JSon.Net to pull the 'thisisinteresting' part of the sub category into a class like:
class Des
{
int id;
string name;
int thisisinteresting;
}
The trivial way would be to actually model your class to the JSON structure:
public class AddedInfo
{
public int thisisinteresting { get; set; }
public string id_str { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
}
Then add a property to the RootObject to emit the property:
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
[JsonIgnore]
public int thisisinteresting { get { return addedInfo.thisisinteresting; } }
}
There are alternatives like creating a custom serializer or using JObject and deserialize the structure yourself, but I won't go into that. If you need to parse the JSON anyway, the price to deserialize it entirely is small.

Flattening nested JSON object in JSON.NET

I have a simple JSON like this:
{
"id": 123,
"name": "BaseName",
"variation": { "name": "VariationName" }
}
Is there a simple way to map it with JSON.NET deserialization to:
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string VariationName { get; set; }
}
I can probably do it with a custom converter, but I hoped there would be a simpler way by annotating the class with attributes which would give instructions to deserialize the variation object just using the one property.
You could set up a class for variation and make VariationName a get-only property
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Variation variation { get; set; }
public string VariationName { get { return variation.VariationName; } }
}
class variation
{
public string name { get; set; }
}

Categories

Resources