I'd like to know which is the best way do Deserialize to Dynamic, using NewtonSoft.Json and C#
The code below works, but I didn't like it. I would like to simplify it, using "named properties".
The main purpose is to get the last object named "results". It is an array of objects.
I know I can use a response object, but I need to use a dynamic or generic object.
var searchprod = wscli.BuscarImagensPorProdutoId(prodSku.ToString());
dynamic obj = JsonConvert.DeserializeObject<dynamic>(searchprod.Result.ToString());
dynamic obj1 = obj.results.ToString();
dynamic obj2 = JsonConvert.DeserializeObject<dynamic>(obj1);
dynamic results = ((JContainer)obj2).ToList();
if (results != null)
{
foreach (IEnumerable<JToken> item in results)
{
var prodId = item.ToList()[0];//id is first position
var id = ((JProperty)prodId).Value.ToString();
if (!string.IsNullOrEmpty(id))
{
//Delete image
var res = await wscli.ExcluirImagemProduto(id);
if (res == null || res is string)
{
throw new Exception($"Error image {id}. Details: {(res == null ? "null" : res.ToString())}");
}
if (res.status == null || res.status.ToString() != "OK")
{
throw new Exception($"Error image {id} and product {prodSku}. Details: {JsonConvert.SerializeObject(res)}");
}
}
}
}
Json:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 62217,
"image": "https://io.com/image1.jpg",
"position": 5,
"title": null,
"video": null,
"add_date": "2022-07-06T22:13:14.538307",
"change_date": "2022-07-06T22:13:14.538331",
"product": 12528,
"skus": []
},
{
"id": 62216,
"image": "https://io.com/image2.jpg",
"position": 4,
"title": null,
"video": null,
"add_date": "2022-07-06T22:13:00.435415",
"change_date": "2022-07-06T22:13:00.435436",
"product": 12528,
"skus": []
},
{
"id": 62215,
"image": "https://io.com/image3.jpg",
"position": 3,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:51.071782",
"change_date": "2022-07-06T22:12:51.071808",
"product": 12528,
"skus": []
},
{
"id": 62214,
"image": "https://io.com/image4.jpg",
"position": 2,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:35.943846",
"change_date": "2022-07-06T22:12:35.943871",
"product": 12528,
"skus": []
},
{
"id": 62213,
"image": "https://io.com/image5.jpg",
"position": 1,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:17.221066",
"change_date": "2022-07-06T22:12:17.221089",
"product": 12528,
"skus": []
}]
}
Thanks
It's not super clear what you don't like about what you have, but if you're looking to be able to access things by path / property name, something like this might work out for you. (getting strings into C# annoys me, I popped it to a file)
[TestMethod]
public void GetNode()
{
string jsonString = File.ReadAllText("json1.json");
Assert.IsNotNull(jsonString);
JObject jObject = JObject.Parse(jsonString);
// selects the node with results
var resultsNode = jObject.SelectToken("$..results");
foreach (JToken item in resultsNode)
{
Console.WriteLine(item["image"]);
}
}
I think reading this article can be useful.
https://inspiration.nlogic.ca/en/a-comparison-of-newtonsoft.json-and-system.text.json
If you have used Newtonsoft.Json features in your existing projects that are missing in System.Text.Json or have heavily decorated your DTO’s with several attributes from Newtonsoft.Json, you will probably encounter many obstacles during migration.
If you are starting a new project, I would recommend using System.Text.Json. Microsoft is constantly improving System.Text.Json and there have been significant improvements between .Net Core 3.1 and .Net 5.0 and Microsoft has already started planning for .Net 6.0.
Related
I am using Mapping object in asp.net core 6. Currently, I want to map two dictionaries in the asp .net core, one has value in key = null and one has value in key != null.
You can see my code below:
public async Task<IDictionary<string, object>> MappingDictionaries(IDictionary<string, object> sourceDict)
{
// Get dictionary from Repository, this dictionary has value in key = null;
var destinationDict = await _myRepository.GetMulti(x => x.ParentID == 0);
// sourceDict is passed by parameter variable and this dictionary has value != null;
}
How can I map properties and values from sourceDict to destinationDict? To check if the properties have been mapped, if yes return destinationDict, otherwise show a notification error.
My source dictionary:
"customerInfo": {
"CustomerName": "A",
"CustomerCode": "ABC",
"DateOfBirdth": "12/02/2020",
"Address": "D",
"PhoneNumber": "12345",
"Gender": "Nam",
"Email": "abc"
},
"provideTime": {
"Hour": "12:00",
"Day": "07",
"Month": "10",
"Year": "2022"
}
My destination dictionary:
"customerInfo": {
"CustomerName": "",
"CustomerCode": "",
"DateOfBirdth": "",
"Address": "",
"PhoneNumber": "",
"Gender": "",
"Email": ""
},
"provideTime": {
"Hour": "",
"Day": "",
"Month": "",
"Year": ""
}
Thanks for your support and sorry for my bad English!
Given a JSON array of:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
},
{
"id": 3,
"name": "def"
}
]
I would expect:
JArray jArray = JArray.Parse(json);
dynamic value = jArray.SelectTokens("$[?(#['name'] == null || #['name'] == 'abc')]");
to produce:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
}
]
This tests correctly using a variety of online JsonPath testers. But when I run it with Json.NET, I am getting:
[
{
"id": 1,
"name": "abc"
}
]
Is it possible for me to change the JsonPath to handle this? Is it the null in the query that is the problem?
For clarity, I need to use JsonPath because it is stored in a configuration file and applied dynamically.
I expect that Newtsoft is considering absence to be different from "present with a null value," whereas the others you've tried consider them to be the same.
I imagine if you update the path to
$[?(!#['name'] || #['name'] == null || #['name'] == 'abc')]
it might work for you.
Alternatively, updating the data to
[
{
"id": 1,
"name": "abc"
},
{
"id": 2,
"name": null
},
{
"id": 3,
"name": "def"
}
]
would also yield the middle item.
We haven't defined this yet in the specification effort, but it's a good one. I'll raise that in an issue.
You can also see there's no consensus among libraries with this test.
With LINQ to JSON you can solve the same problem like this:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JArray.Parse(json);
var filteredJson = from item in semiParsedJson
let name = (string)item["name"]
where name == null || name == "abc"
select item;
Console.WriteLine(new JArray(filteredJson));
The output will be as expected:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
}
]
I have a list of collection (objects) where I need to ascii sort them by a specific key (value)
I have tried but all I can find anywhere is a list of strings being ascii sorted instead of objects.
var myList = new List();
And this mylist is as below:
[
{
"parent": null,
"Id": 14108,
"value": ""
},
{
"parent": null,
"Id": 14109,
"value": null
},
{
"parent": null,
"Id": 14113,
"value": "1ab"
},
{
"parent": null,
"Id": 14114,
"value": "11b"
},
{
"parent": null,
"Id": 14115,
"value": "a10"
},
{
"parent": null,
"Id": 14111,
"value": "a1234"
}
]
I expect the list to be sorted by the value in ascii order but seems a problem only solved by list of strings in c#
You need to pass an IComparer to your sort method or use a lambda to identify which property should be used to sort. In your example it looks something like myList.Sort( f => f.value )
given
List<MyInterfaceObject> mylist;
then
mylist.Sort(x => x.value);
I want to extract the first value in a JSONArray as String. Somehow I have the wrong approach, I get an exception.
How can I improve this?
I think I reach the array fine via myJasonObject["entities"].toArray(), but when I try to do something like getString()["entity"] afterwards, it's marked as error by VS.
I want to be able to store "dax" (the value of "entity"):
Response{
"query": "what about dax",
"topScoringIntent": {
"intent": "StockPrice2",
"score": 0.3969668
},
"intents": [
{
"intent": "StockPrice2",
"score": 0.3969668
},
{
"intent": "None",
"score": 0.372112036
},
],
"entities": [
{
"entity": "dax",
"type": "StockSymbol"
}
]
}
You can get "dax" using following:
JObject obj = JObject.Parse(json);
JArray entities = obj.GetValue("entities") as JArray;
var firstEntity = entities.FirstOrDefault() as JObject;
var entityPropertyValue = entity.GetValue("entity");
var daxString = entityPropertyValue.ToString();
I have a JSON string that I'm getting from Facebook API, in which I have a node whose name changes according to its content, for example some time it is 45, or 58 etc.
It could be any number.
I want its value. How to get it?
Example:
{
"data": [
{
"id": "1492292372_10201810786059989",
"created_time": "2014-04-05T09:00:54+0000"
},
{
"id": "1492292372_10201804679827337",
"created_time": "2014-04-04T07:29:07+0000"
},
{
"id": "1492292372_10201804649306574",
"created_time": "2014-04-04T07:10:33+0000"
},
{
"id": "1492292372_10201801316823264",
"created_time": "2014-04-03T18:31:50+0000"
},
{
"id": "1492292372_10201798962284402",
"created_time": "2014-04-03T06:24:47+0000"
},
{
"message_tags": {
"0": [
{
"id": "1492292372",
"name": "Yawar Sohail",
"type": "user",
"offset": 0,
"length": 12
}
],
"15": [
{
"id": "1489845168",
"name": "Zeeshan Anjum",
"type": "user",
"offset": 15,
"length": 13
}
]
},
"id": "1492292372_10201796274777216",
"created_time": "2014-04-02T17:57:05+0000"
},
{
"id": "1492292372_10201794080482360",
"created_time": "2014-04-02T07:26:23+0000"
},
Inside message_tags there are two nodes [0 and 15] they dynamically changes according to their offset values. I want names, type and ids inside these nodes.
You can deserialize your JSON into an ExpandoObject:
var converter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, converter);
Which dynamically adds members to your object at runtime, and allows you to iterate over them as described in this answer:
foreach (var prop in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("Name: {0}, Value: {1}",prop.Name, prop.GetValue(obj,null));
}
That way you can iterate over obj.message_tags to get the individual messages, and obtain all their details respectively.