aspnet core json ignore duplicate fields - c#

How do I ignore duplicate fields?
For example I have this raw json { "Value": 3, "Name": "Test", "value": "irrelevant" }
I would like to ignore value because my target type has public int Value { get; set; }
We have this kind of issue on most of the data from the client side views. In asp.net core, how do we instruct the json serializer to use the property that matches the type in the target?
Cheers,

Unfortunately, this isn't possible.
Assuming this JSON:
{
"Value": 3,
"Name": "Test",
"value": "irrelevant"
}
And this class:
public class MyClass
{
public string Value { get; set; }
public string Name { get; set; }
}
JSON.NET will deserialize as follows:
Value = 3
Name = "Test"
Value = "irrelevant"
The deserializer doesn't have a "state" so it doesn't care if Value was previously deserialized; it simply assigns the properties as it goes.
The reason you're getting an error is that your class defines Value as an int. This results in the deserializer executing:
Value = 3
Name = "Test"
Value = "irrelevant" <--- throw exception because int can't be set to a string value.

Related

Remove property name from the response

public class CarsModel
{
public int OnStock { get; set; }
public int Rented { get; set; }
public List<CarInfo> Cars { get; set; }
}
public class CarInfo
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public CarDetails Details { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public ServiceInfo ServiceInfo { get; set; }
[JsonProperty( NullValueHandling = NullValueHandling.Ignore)]
public MarketingInfo MarketingInfoDetails { get; set; }
}
Depending on the scenario this cars property will have different representation (either MarketingInfo or CarDetails or ServiceInfo, but not both).
case 1: MarketingInfo
"onStock": 11,
"rented": 2,
"cars": [{
"carId": 1,
"MarketingInfo": {
"contactPerson": "John Smith"
}, ...
}]
case 2: ServiceInfo and CarDetails
"onStock": 11,
"rented": 2,
"cars": [{
"ServiceInfo": {
"lastService": "2021-01-01"
},
"CarDetails": {
"carId": 1,
"lastOwner": "Mister Clark"
}, ...
}]
This is how I populate my response
var carsModel = new CarsModel{
OnStock = 11,
Rented = 2
};
foreach (var car in cars)
{
carsModel.Cars.Add(new CarsModel
{
MarketingInfoDetails = new MarketingInfo
{
ContactPerson = "John Smith",
....
}
});
}
In the above model representation my response is NOT as I want them to be (because it contains marketingInfoDetails word)
Response:
{
"data" :[{
"onStock": 11,
"rented": 2,
"cars": [
{
"marketingInfoDetails": {
"contactPerson": "John Smith",
...
}
}]
}]
}
where I want to be represented without name "marketingInfoDetails"
{
"data" : [{
"onStock" : 11,
"rented" : 2,
"cars" : [{ "contactPerson" : "John Smith"}]
}]
}
Please share if you think this response for the described scenario can be modeled better.
Your C# model and result JSON are matching. What you're asking for changes from the start of your question to the end of your question. What you appear to want from the C# model and JSON is to remove the object which your desired example includes alongside a carId property that is not present in your C# models.
You need to remove the intermediate CarInfo class and instead have your list of cars be a common interface which is inherited by CarDetails, ServiceDetails, and MarketingInfo, then you will not see the "MarketingInfoDetails" property in your JSON.
If you were to instead add the carId property to CarInfo and again serialize the C# model to JSON, you will see that your current model matches exactly what you first stated you want the JSON to look like.
If you are using Json.net, you could make use of Conditional Serialization functionality using ShouldSerialize.
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.
You would need to modify your DTOs to include an additional property and method (for each property you want to make conditional) as the following.
[JsonIgnore]
public bool SerializeDetails{get;set;} = true;
public bool ShouldSerializeDetails() =>SerializeDetails;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public CarDetails Details { get; set; }
[JsonIgnore]
public bool SerializeMarketingInfoDetails{get;set;} = true;
public bool ShouldSerializeMarketingInfoDetails() =>SerializeMarketingInfoDetails;
[JsonProperty( NullValueHandling = NullValueHandling.Ignore)]
public MarketingInfo MarketingInfoDetails { get; set; }
For each instance of CarDetails, you could now set the SerializeMarketingInfoDetails or SerializeDetails properties to conditional serialize them.
Demo Code
It'a recommended that you use EmiDefaultValue="true" for datamembers.
In the case the proprety is null, it won't be shown in the jsonsince its value is null.

Deserialize JSON with $ in property names

I have the following JSON object (the shape of the object will vary hence use of dynamic):
{
"mba$maccType": [{
"class": {
"id": 1057,
"intlId": "cacc"
},
"classA": false,
"endDate": "4712-12-31T00:00:00",
"histStatus": {
"id": 5,
"intlId": "valid"
},
"objClassif": {
"id": 74,
"intlId": "mba$macc_type"
},
"secUser": {
"id": 2
},
"startDate": "2018-12-01T00:00:00",
"timestamp": "2020-01-18T07:29:21"
}
]
}
I'm using Newtonsoft.Json to parse as follows:
dynamic dyn = JObject.Parse(json);
My problem is, I'm unable to reference any dynamic properties because the parent property containing the $ gives a syntax error:
Console.WriteLine(dyn.mba$maccType);
How can I get to the value of "class.intlId" (i.e. "cacc")?
You can parse your JSON to JObject instead of dynamic type and access its items by key. Like get the first item from mba$maccType (since it's an array), then access a class token and intlId value from it
var jObject = JObject.Parse(json);
var firstItem = jObject["mba$maccType"]?.FirstOrDefault();
var result = firstItem?["class"]?["intlId"]?.ToString(); // returns "cacc"
Supposing that the only dynamic part of your JSON structure are the property names on the outer object, you can deserialize this JSON to a Dictionary<string, List<T>>. The benefit of doing this is that you would have clearly defined types for almost everything that's deserialized.
// type definitions
class ClassRecord
{
public int id { get; set; }
public string intlId { get; set; }
}
class Item
{
public ClassRecord #class { get; set; }
public bool classA { get; set; }
// etc.
}
// deserialize
var obj = JsonConvert.DeserializeObject<Dictionary<string, List<Item>>>(json);
Console.WriteLine(obj["mba$maccType"][0].#class.id); // 1057

How to query into a JSON getting using LINQ?

JSON
{
"count": 3,
"value": [
{
"id": "AAAAAAAAAAAAA",
"description": "test1",
"name": "name1"
},
{
"id": "BBBBBBBBBB",
"description": "test2",
"name": "name2"
},
{
"id": "CCCCCCCCCCCC",
"description": "test3",
"name": "name3"
}
]
}
I have a code in my solution retrieving from a LIST api and giving the JSON above.
How can I use a LINQ to retrieve specific values? (e.g) I need to select name1 and I will get the id,description,name values.
I am using a dynamic variable in my code:
dynamic json = JObject.Parse(client.GetString().Result);
I'd been tinkering with other online guides the past few hours. However, can't get the result right.
Please help.
One solution would be to deserialize your JSON string into C# objects and then use Linq to get a specific object.
C# class definitions:
public class Content
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("value")]
public List<Value> Values { get; set; }
public Content()
{
Values = new List<Value>();
}
}
public class Value
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
Deserializing and getting the object:
string json = #"{
""count"": 3,
""value"": [
{
""id"": ""AAAAAAAAAAAAA"",
""description"": ""test1"",
""name"": ""name1""
},
{
""id"": ""BBBBBBBBBB"",
""description"": ""test2"",
""name"": ""name2""
},
{
""id"": ""CCCCCCCCCCCC"",
""description"": ""test3"",
""name"": ""name3""
}
]
}";
Content content = JsonConvert.DeserializeObject<Content>(json);
Value value = content.Values.FirstOrDefault(x => x.Name.Equals("name1", StringComparison.InvariantCultureIgnoreCase));
First, you can create a class to represent a client:
public class Client
{
public string Id { get; set; }
public string Description { get; set; }
public string Name { get; set; }
}
With this class, you can use JObject.Parse (as you're already doing) to parse the JSON into something that can be queried, use SelectToken to pull out the value array and then use ToObject to convert that to a list of Clients. Here's what that looks like:
var jsonObject = JObject.Parse(json_source);
var jsonObjectValue = jsonObject.SelectToken("value");
var clients = jsonObjectValue.ToObject<List<Client>>();
Once you've got your clients variable, you can use a simple LINQ statement to find the one that is name1:
var clientWithName1 = clients.SingleOrDefault(x => x.Name == "name1");
In this case, clientWithName will be null if no such client was found.
Here's a dotnetfiddle that demonstrates a complete solution.
Create an object Client that has properties id, description and name. Deserialize the json into a list of these objects.
List<Client> clients = JsonConvert.Deserialize<List<Client>>(json_source);
string desc = clients[0].description;
Apparently with fiddling with my code I found an answer for myself.
Thanks for to the ones trying to help me for giving me ideas.
var requestWorkProcess = await client.GetStringAsync("my url");
var workProcessId = JObject.Parse(requestWorkProcess)["value"].Children<JObject>().FirstOrDefault(o => o["name"].ToString() == workProcess).GetValue("id");

Deserializing a list of objects with different names in JSON.NET

I'm getting my data from a website which returns a .json format that is quite unfamiliar to me. I've been looking for the solution for a couple of hours, and I must be using the terminology.
The json is formatted something like this:
[
{
"Foo": {
"name": "Foo",
"size": {
"human": "832.73kB",
"bytes": 852718
},
"date": {
"human": "September 18, 2017",
"epoch": 1505776741
},
}
},
{
"bar": {
"name": "bar",
"size": {
"human": "4.02MB",
"bytes": 4212456
},
"date": {
"human": "September 18, 2017",
"epoch": 1505776741
}
}
}]
I'm using Newtonsoft's JSON.NET, and I can't seem to be able to create a data structure that would allow me to deserialize it, since it's the array of classes with different names. Specifically the property names "Foo" and "bar" could differ at runtime. Property names elsewhere in the JSON hierarchy are known.
Assuming that only the names "Foo" and "Bar" are unknown at compile time, you can deserialize that JSON into a List<Dictionary<string, RootObject>>, where RootObject is a c# model I generated automatically using http://json2csharp.com/ from the JSON for the value of "Foo".
Models:
public class Size
{
public string human { get; set; }
public int bytes { get; set; }
}
public class Date
{
public string human { get; set; }
public int epoch { get; set; }
}
public class RootObject
{
public string name { get; set; }
public Size size { get; set; }
public Date date { get; set; }
}
Deserialization code:
var list = JsonConvert.DeserializeObject<List<Dictionary<string, RootObject>>>(jsonString);
Notes:
The outermost type must be an enumerable such List<T> since the outermost JSON container is an array -- a comma-separated sequence of values surrounded by [ and ]. See Serialization Guide: IEnumerable, Lists, and Arrays.
When a JSON object can have arbitrary property names but a fixed schema for property values, it can be deserialized to a Dictionary<string, T> for an appropriate T. See Deserialize a Dictionary.
Possibly bytes and epoch should be of type long.
Working .Net fiddle.

How to parse Json to class in c# (Windows phone 8)?

Maybe someone knows better version to resolve my problem?
Have next json:
[
{
"name":{
"IsEmpty":false,
"X":-10.5,
"Y":2.47
},
"password":"pas"
},
{
"name":{
"IsEmpty":false,
"X":-10.5,
"Y":2.47
},
"password":"pas"
},
{
"name":{
"IsEmpty":false,
"X":-10.5,
"Y":2.47
},
"password":"pas"
}
]
I want parse elements from json to my classes:
public class Name
{
public bool IsEmpty { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
public class RootObject
{
public List<Name> name { get; set; }
public string password { get; set; }
}
......
dynamic res = JsonConvert.DeserializeObject<RootObject[]>(result1);
Variable result1 is my json object.
And exeption, what I have:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type 'client_app.MainPage+RootObject[]' because the type requires
a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this
error either change the JSON to a JSON array (e.g. [1,2,3]) or change
the deserialized type so that it is a normal .NET type (e.g. not a
primitive type like integer, not a collection type like an array or
List) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to
deserialize from a JSON object. Path 'name', line 1, position 8.
The problem resides in the mapping between your JSon string and your root object. I think that this is what causes the problem:
"IsEmpty":false
When deserializing your object the JSon converter waits for the IsEmpty property to be of type bool.
Which is not the case since its type is List
So your root class should be like this:
public class RootObject
{
public Name name { get; set; }
public string password { get; set; }
}
Please try like this:
var res = JsonConvert.DeserializeObject<List<RootObject>>(result1);
This is the set of classes you need to deserialize
public class Name
{
public bool IsEmpty { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
public class Item
{
public Name name { get; set; }
public string password { get; set; }
}
then
var items = Newtonsoft.Json.JsonConvert.DeserializeObject<Item[]>(json);
var ds = new DataContractJsonSerializer(typeof(RootObject[]));
var msnew = new MemoryStream(Encoding.UTF8.GetBytes(MyJsonString));
RootObject[] items = (RootObject[])ds.ReadObject(msnew);
This resolve my problem
Your Name class has the property of IsEmpty as a List of bools.
So you Json should be:
[
{
"name": {
"IsEmpty": [
false
],
"X": -10.5,
"Y": 2.47
},
"password": "pas"
},
{
"name": {
"IsEmpty": [
false
],
"X": -10.5,
"Y": 2.47
},
"password": "pas"
},
{
"name": {
"IsEmpty": [
false
],
"X": -10.5,
"Y": 2.47
},
"password": "pas"
}
]
Note the sqaure brackets on the value of IsEmpty, which signifies the value is in a collection. if you want to assign more than one value then you can add more using:
"IsEmpty": [ false, true ]

Categories