Json.Encode object with array string to "[ ]" instead of null - c#

I'm using de Json.Encode(object) function to convert my object to a json.
The problem is I have a string array property (headers) and I want to convert it to { 'headers': [] } instead of { 'headers': null } when it's empty.
My class:
public class BaseObject
{
public LinkModel Links { get; set; }
}
public class LinkModel
{
public SelfLinkModel Self { get; set; }
}
public class SelfLinkModel
{
public string Uri { get; set; }
public string Method { get; set; }
public string[] Headers { get; set; }
}
And the Encoding:
string content = Json.Encode(profile);
To sum up, it converts to:
{
"Links":{
"Self":{
"Uri":"href",
"Method":"GET",
"Headers":null
}
}
}
And I want:
{
"Links":{
"Self":{
"Uri":"href",
"Method":"GET",
"Headers": []
}
}
}

One option would be to initialise the property to an empty array. Do it in the class constructor like this:
public class SelfLinkModel
{
public SelfLinkModel()
{
Headers = new string[0];
}
public string Uri { get; set; }
public string Method { get; set; }
public string[] Headers { get; set; }
}

Related

Deserialize a json object with multiple nested objects /lists using JsonConvert

I a beginner in C# application development and have the following json data which I want to de-serialize:
{
"Parameters": [
{
"Info": {
"Id": 0,
"No": "0001"
},
"IntOptions": [
{
"Value": 0,
"ValInfo": "FIFO"
},
{
"Value": 1,
"ValInfo": "FIFO2"
}
],
"BubbleList": [
{
"Position": 0,
"SubBubbleList": [
{
"Value": 0,
"Message": "ListObj1"
},
{
"Value": 1,
"Message": "ListObj2"
}
]
}
]
}
]
}
I have the class structure defined as follows:
public class ParamList
{
private List<Param> _param = new List<Param>();
[JsonProperty("Parameters")]
public IReadOnlyCollection<Param> Param { get => _param.AsReadOnly(); }
}
public class Param
{
private List<IntOptions> _intOptions;
private List<BubbleList> _bubbleList;
[JsonProperty("Info")]
public Info? Info { get; }
[JsonProperty("IntOptions")]
public IReadOnlyCollection<IntOptions> IntOptionsVar { get => _intOptions.AsReadOnly(); }
[JsonProperty("BubbleList")]
public IReadOnlyCollection<BubbleList> BubbleListVar { get => _bubbleList.AsReadOnly(); }
}
public class Info
{
public Info(int id, string number)
{
Id = id;
Number = number;
}
[JsonProperty("Id")]
public int Id { get; private set; }
[JsonProperty("No")]
public string Number { get; private set; }
}
public class IntOptions
{
public IntOptions(int value, string valInfo)
{
Value = value;
ValInfo = valInfo;
}
[JsonProperty("Value")]
public int Value { get; private set; }
[JsonProperty("ValInfo")]
public string ValInfo { get; private set; }
}
public class BubbleList
{
private List<SubBubbleList>? _subBubbleList;
public BubbleList(int position)
{
Position = position;
}
[JsonProperty("Position")]
public int Position { get; private set; }
[JsonProperty("SubBubbleList")]
public IReadOnlyCollection<SubBubbleList> SubBubbleListVar { get => _subBubbleList.AsReadOnly(); }
}
public class SubBubbleList
{
public SubBubbleList(int value, string message)
{
Value = value;
Message = message;
}
[JsonProperty("Value")]
public int Value { get; private set; }
[JsonProperty("Message")]
public string Message { get; private set; }
}
I came up with the following de-serializing code which results in an empty list of Param:
try
{
ParamList paramList = JsonConvert.DeserializeObject<ParamList>(readJsonContent);
Console.WriteLine(paramList);
}
This gives me an empty list of Param.
I read a lot of articles explaining about de-serializing a json object, however, could not find one which would solve my use case. I need to understand what am I doing wrong here. I need to have a List<Param> which would then have Info, List<IntOptions>, & List<BubbleList> -> List<SubBubbleList>.
Is this achievable by just de-serializing the json data, or will I have to iterate through individual objects?
you have only getters in your classes. you need setters to assign values from json to c# objects
List<Parameter> Parameters = JsonConvert.DeserializeObject<ParamList>(json).Parameters;
classes
public class ParamList
{
public List<Parameter> Parameters { get; set; }
}
public class Parameter
{
public Info Info { get; set; }
public List<IntOption> IntOptions { get; set; }
public List<BubbleList> BubbleList { get; set; }
}
public class BubbleList
{
public int Position { get; set; }
public List<SubBubbleList> SubBubbleList { get; set; }
}
public class Info
{
public int Id { get; set; }
public string No { get; set; }
}
public class IntOption
{
public int Value { get; set; }
public string ValInfo { get; set; }
}
public class SubBubbleList
{
public int Value { get; set; }
public string Message { get; set; }
}
but if for some reasons you still need readonly you can change ALL your read only classes by moving json property name using this template
public class ParamList
{
[JsonProperty("Parameters")]
private List<Param> _param = new List<Param>();
public IReadOnlyCollection<Param> Param
{
get => _param.AsReadOnly();
}
}

How to generate a JSON class with dynamic name

I don't know if there is an existing name for that case, but I'm trying to retrieve data from NASA API (https://api.nasa.gov/) and I have a simple challenge to catch a list of objects near earth. Here is the JSON response I have from the GET request I do to "https://api.nasa.gov/neo/rest/v1/feed?...."
{
"links": {
"next": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-04&end_date=2021-07-04&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"prev": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-02&end_date=2021-07-02&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"self": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-03&end_date=2021-07-03&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"element_count": 6,
"near_earth_objects": {
"2021-07-03": [
{
"links": {
"self": "http://www.neowsapp.com/rest/v1/neo/3701710?api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"id": "3701710",
"neo_reference_id": "3701710",
"name": "(2014 WF497)",
"nasa_jpl_url": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=3701710",
"absolute_magnitude_h": 20.23,
"estimated_diameter": {
"kilometers": {
}
And that's the way it is built in Visual Studio (using the Special Paste option for JSON)
public class NearEarthObject
{
public Links links { get; set; }
public int element_count { get; set; }
public Near_Earth_Objects near_earth_objects { get; set; }
}
public class Links
{
public string next { get; set; }
public string prev { get; set; }
public string self { get; set; }
}
public class Near_Earth_Objects
{
public _20210703[] _20210703 { get; set; }
}
public class _20210703
{
public Links1 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 question is, inside of the element "near_earth_objects", there is an element called "2021-07-03" (the date of the data I requested), the problem is that I am trying to include it into a DataGridView made in .NET C# (Windows Forms, but that doesn't matters here, I think) and the user wants to get the information by date. So, "2021-07-03" is a valid member just for one day, and the user should be able to get data from multiple days.
So, is there a way in C# to get all child objects inside of near_earth_objects without knowing their names since there will be the option to search for asteroids from date X to Y in my application?
Using System.Text.Json
The API response will map to the following classes
public class Neo
{
public Links Links { get; set; }
public int ElementCount { get; set; }
public Dictionary<string, List<NearEarthObject>> NearEarthObjects { get; set; }
}
public class Links
{
public string Next { get; set; }
public string Prev { get; set; }
public string Self { get; set; }
}
public class NearEarthObject
{
public Links Links { get; set; }
public string Id { get; set; }
public string Name { get; set; }
// Other properties
}
The NearEarthObjects is simply a Dictionary, where the key is the formatted date and value is a List containing NearEarthObject
The PropertyNamingPolicy will allow us to support the API's underscore property naming convention.
public class UnderscoreNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
return name.Underscore();
}
}
Example usage
// using using System.Text.Json;
var response = await new HttpClient().GetStringAsync(url);
var neo = JsonSerializer.Deserialize<Neo>(response, new JsonSerializerOptions
{
PropertyNamingPolicy = new UnderscoreNamingPolicy()
});
foreach(var neos in neo.NearEarthObjects)
{
Console.WriteLine(neos.Key);
}
use System.Text.Json, JsonNamingPolicy
demo code
public class DynamicNamePolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
var today = DateTime.Today.ToString("yyyy-MM-dd");
if (name.Equals("DateData")) //model property name
return today; //convert to json string property name
return name;
}
}
//data deserialize
string data = ""; //json string
var obj = JsonSerializer.Deserialize<NearEarthObject>(data, new JsonSerializerOptions
{
PropertyNamingPolicy = new DynamicNamePolicy(),
});

Not able validate data condition based on the json element attribute value from a json using c#

I have a json file, where i have to validate a json attribute element value based on another json element attribute value. But if there json elements with the same name. It always takes the last value always instead of parsing the json data fully. Please guide me.
Below the sample json file
{
"PLMXML":{
"language":"en-us",
"author":"Developer",
"date":"2020-05-22",
"traverseRootRefs":"#id6",
"Operation":{
"id":"id21",
"subType":"BS4_BaOP",
"catalogueId":"70700000209604"
},
"Operation":{
"id":"id28",
"subType":"BS4_BaOP",
"catalogueId":"70700000209603"
},
"OperationRevision":{
"id":"id6",
"subType":"BS4_BaOPRevision",
"masterRef":"#id21",
"revision":"A1"
}
}
}
And below the code which im trying to use
public void Readjsonfile(string jsondata)
{
var message = JsonConvert.DeserializeObject<plmxmldatamodel>(jsondata);
if (String.Equals(message.PLMXML.traverseRootRefs.Substring(1), message.PLMXML.OperationRevision.id))
{
Console.WriteLine("Condtion1");
if (String.Equals(message.PLMXML.OperationRevision.masterRef.Substring(1), message.PLMXML.Operation.id))
{
Console.WriteLine("Condition_2");
//Do something based on the condtion
}
}
}
public class Operation
{
public string id { get; set; }
public string subType { get; set; }
public string catalogueId { get; set; }
}
public class OperationRevision
{
public string id { get; set; }
public string subType { get; set; }
public string masterRef { get; set; }
}
public class PLMXML
{
public string language { get; set; }
public string author { get; set; }
public string date { get; set; }
public string traverseRootRefs { get; set; }
public Operation Operation { get; set; }
public OperationRevision OperationRevision { get; set; }
}
public class plmxmldatamodel
{
public PLMXML PLMXML { get; set; }
}
When i try to dedug this in the second if condtion, the value for message.PLMXML.Operation.id is always id28 , because of which second if condition fails. While the first if condition is passed as there is only one message.PLMXML.OperationRevision.id. i wanted behaviour where it would check complete json data and check if message.PLMXML.Operation.id with value id21 is present or not , So my data gets passed. Please kindly guide me here.I am very new to C# here.
From my observation you have couple of issues.
What happen you have double keys, and your parser taking the last value not the first one.
First of all your json should be corrected. I assume you have access to change your json and operation should be an array like follow:
{
"PLMXML":{
"language":"en-us",
"author":"Developer",
"date":"2020-05-22",
"traverseRootRefs":"#id6",
"Operations":[
{
"id":"id21",
"subType":"BS4_BaOP",
"catalogueId":"70700000209604"
},
{
"id":"id28",
"subType":"BS4_BaOP",
"catalogueId":"70700000209603"
}
],
"OperationRevision":{
"id":"id6",
"subType":"BS4_BaOPRevision",
"masterRef":"#id21",
"revision":"A1"
}
}
}
When array in place than use an online tool like to validate your json and use this tool to create a model.
Your model will be like this:
public partial class PlmxmlDataModel
{
[JsonProperty("PLMXML")]
public Plmxml Plmxml { get; set; }
}
public partial class Plmxml
{
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("date")]
public DateTimeOffset Date { get; set; }
[JsonProperty("traverseRootRefs")]
public string TraverseRootRefs { get; set; }
[JsonProperty("Operations")]
public Operation[] Operations { get; set; }
[JsonProperty("OperationRevision")]
public OperationRevision OperationRevision { get; set; }
}
public partial class OperationRevision
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("subType")]
public string SubType { get; set; }
[JsonProperty("masterRef")]
public string MasterRef { get; set; }
[JsonProperty("revision")]
public string Revision { get; set; }
}
public partial class Operation
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("subType")]
public string SubType { get; set; }
[JsonProperty("catalogueId")]
public string CatalogueId { get; set; }
}
And your method like this:
public void Readjsonfile(string jsondata)
{
var message = JsonConvert.DeserializeObject<PlmxmlDataModel>(jsondata);
if (String.Equals(message.Plmxml.TraverseRootRefs.Substring(1), message.Plmxml.OperationRevision.Id))
{
Console.WriteLine("Condtion1");
if (String.Equals(message.Plmxml.OperationRevision.MasterRef.Substring(1), message.Plmxml.Operations[0].Id))
{
Console.WriteLine("Condition_2");
//Do something based on the condtion
}
}
}
Now in your method I am looking for array index 0 with contain id 28, but if you are look for id 28 in any of the array then you can do some thing like:
if (message.Plmxml.Operations.Any(e => e.Id == message.Plmxml.OperationRevision.MasterRef.Substring(1)))

Creating an array in C# that contains an object

I have a RequestModel that contains some properties and another class Consignment.
Calling JsonConvert.SerializeObject(this); returns
{ "consignment": { "collectionDetails": null } }
Instead I would like to return an array of the object
"consignment": [ { "collectionDetails": null } ]
I've tried to create Consignment[] but get a conversion issue.
I've also tried to create a List<Consignment>
class RequestModel
{
public string job_id { get; set; }
public Consignment consignment = new Consignment();
public class Consignment
{
public string consignmentNumber { get; set;
}
public string ToJSON()
{
return JsonConvert.SerializeObject(this);
}
Here you go:
public class RequestModel
{
public string job_id { get; set; }
public Consignment consignment { get; set; }
public RequestModel()
{
consignment = new Consignment();
}
public string ToJSON()
{
return JsonConvert.SerializeObject(this);
}
}
Then your Consignment DTO would look like this assuming you have a CollectionItems class (didn't see any code in question around this):
public class Consignment
{
public List<CollectionItems> collectionDetails { get; set; }
public Consignment()
{
collectionDetails = new List<Collection>();
}
}

using JSON response from REST api with nonstandard names

{"balances-and-info":{"on_hold":[],"available": {"USD":0.93033384},"usd_volume":"243.18","fee_bracket": {"maker":"0.00","taker":"0.60"},"global_usd_volume":"0.09942900"}}
I have this JSON response, and I'm trying to store it in an object, however as you can see "balances-and-info" cannot be used as a variable name. The method I have been using is:
RestClient client = new RestClient("http://currency-api.appspot.com/api/");
RestRequest request = new RestRequest(url);
var response = client.Execute<Currency>(request);
Currency obj = response.Data;
Where obviously the class is a lot easier
public class Currency
{
public string rate { get; set; }
}
So how can I handle this?
String.replace() balances-and-info with balances_and_info
in your code
YourObject deserialized = parseResponse(obj.replace("balances-and-info", "balances_and_info"));
YourObject parseResponse(string response) {
try
{
// https://www.nuget.org/packages/Newtonsoft.Json/
// Json.NET
YourObject ret = JsonConvert.DeserializeObject<YourObject>(response);
return ret;
}
catch (JsonSerializationException)
{
// do something
}
return null;
}
YourObject
Use http://json2csharp.com/ and generate your object (copy response string, replace balances-and-info with balances_and_info and generate)
public class Available
{
public double USD { get; set; }
}
public class FeeBracket
{
public string maker { get; set; }
public string taker { get; set; }
}
public class BalancesAndInfo
{
public List<object> on_hold { get; set; }
public Available available { get; set; }
public string usd_volume { get; set; }
public FeeBracket fee_bracket { get; set; }
public string global_usd_volume { get; set; }
}
public class YourObject
{
public BalancesAndInfo balances_and_info { get; set; }
}

Categories

Resources