Deserializing a .json file to a dictionary in c# - c#

I am trying to deserialize a dictionary that I was able to already serialize into a .json file.
I made have a class 'Schedule' that is basically the following:
Dictionary<Dag, Stack<Training>>
In my data layer I have the following .json file:
{
"FullSchedule": {
"Maandag": [
{
"Name": "test",
"Description": "test",
"Trainingsort": 0,
"Hours": 1,
"Minutes": 0
}
],
"Dinsdag": [],
"Woensdag": [
{
"Name": "test",
"Description": "test",
"Trainingsort": 0,
"Hours": 0,
"Minutes": 30
}
],
"Donderdag": [],
"Vrijdag": [],
"Zaterdag": [],
"Zondag": []
}
}
As you can see it has the days with a stack of Training objects. But I am not able to deserialize it back to the dictionary as shown above.
It's a school project so I can't use the Newtonsoft and I have to use System.Text.JSON
This is the code i have at the moment:
public static Dictionary<string, Stack<Training>> ReadJSON(string path)
{
if (!Directory.Exists(path)) throw new ArgumentException("Path does not exist");
// First read the file in as a string, then parse it
string scheduleString = "";
try
{
using (StreamReader sr = new StreamReader($#"{path}.json"))
{
scheduleString = sr.ReadToEnd();
}
}
catch (Exception e) { throw new Exception(e.Message); }
var schedule = JsonSerializer.Deserialize<Dictionary<string, Stack<Training?>>>(scheduleString);
return schedule;
}
Thanks in advance!

you can parse json string and after this to deserialize a FullSchedule value
var jsonDocument = JsonDocument.Parse(scheduleString);
Dictionary<string, Stack<Training?>> schedule = jsonDocument.RootElement
.GetProperty("FullSchedule").Deserialize<Dictionary<string, Stack<Training?>>>();

According to how it looks, your json will be deserialized in such class:
public class SomeClass
{
public Dictionary<string, Stack<Training?>> FullSchedule { get; set; }
}
...
var schedule = System.Text.Json.JsonSerializer.Deserialize<SomeClass>(jsonString);

Related

How to add a new property in a specific level on Json using C#

I have a Json as below
{
"name": "123",
"properties": {
"pcName-A": {
"model": "xyz"
}
}
}
I want to add a property as below
{
"name": "123",
"properties": {
"pcName-A": {
"model": "xyz"
},
"pcName-B": {
"model": "xyz"
}
}
}
I am using Newtonsoft library and do as below
var jsonObj = JObject.Parse("jsonString");
jsonObj.SelectToken("properties").Children().First().AddAfterSelf(
new JProperty(pcName-B,
new JObject(
new JProperty("model", xyz))));
Normally if I want to add property in top level I used to do as below
var propertyObjectToAdd = new JObject():
jsonObj.Add("property1", propertyObjectToAdd);
OR
jsonObj["property1"] = propertyObjectToAdd
Is this kind of easy way is not there for the above example?
You just need to get the properties value as a JObject via a cast - then you can call Add on it to add the new property:
using Newtonsoft.Json.Linq;
using System;
using System.IO;
class Program
{
static void Main()
{
string initialJson = File.ReadAllText("test.json");
var jsonObj = JObject.Parse(initialJson);
var properties = (JObject) jsonObj["properties"];
properties.Add(new JProperty("pcName-B", new JObject { ["model"] = "xyz" }));
Console.WriteLine(jsonObj);
}
}
Instead of Add you could use:
properties["pcName-B"] = new JObject { ["model"] = "xyz" };
... but I don't know whether there's any guarantee that the new property would come after the existing one.

Cannot write the correct value on Json file

I'm trying to write a function that wirte on my Json file the value I enter on PostMan
I have my Json file as following:
[
{
"targets":[
"192.168.1.101:9182",
"192.168.1.103:9100",
"192.168.1.105:9182"
]
}
]
M tried to for example a target with the following query:
{
"targets": [
"192.168.1.117:9100"
]
}
Here is my class model:
public class targetResponse
{
public IList<string> targets { get; set; }
}
using postman as shown in the picture:
Everything works fine in the part of prometheus (gives me no error).
Here is the function that I use:
[HttpPost]
[ProducesResponseType(typeof(targetResponse), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<targetResponse>> PostNewInstanceToConfig([FromBody] targetResponse _target)
{
IList<targetResponse> myList = new List<targetResponse>();
var jsonString = System.IO.File
.ReadAllText(_filePath);
myList = JsonConvert.DeserializeObject<List<targetResponse>>(jsonString);
myList.FirstOrDefault().targets.Add(_target.ToString());
StreamWriter myWriter = new StreamWriter(_filePath);
JsonSerializer mySerializer = new JsonSerializer();
mySerializer.Serialize(myWriter, myList);
myWriter.Close();
return null;
}
It opens the file and write following thing, I dont understand why it doesnt why:
[
{
"targets": [
"192.168.1.101:9182",
"192.168.1.103:9100",
"192.168.1.105:9182",
"ApplicationTestCRUD_JSON.targetResponse",
"ApplicationTestCRUD_JSON.targetResponse"
]
}
]
The "ApplicationTestCRUD_JSON" is the name of my project.
Any help please?
EDIT:
I added a foreach loop and removed .toString() method, my function now looks like this:
[HttpPost]
[ProducesResponseType(typeof(targetResponse), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<targetResponse>> PostNewInstanceToConfig([FromBody] targetResponse _target)
{
IList<targetResponse> myList = new List<targetResponse>();
var jsonString = System.IO.File
.ReadAllText(_filePath);
myList = JsonConvert.DeserializeObject<List<targetResponse>>(jsonString);
foreach(var x in _target.targets)
{
myList.FirstOrDefault().targets.Add(x);
}
StreamWriter myWriter = new StreamWriter(_filePath);
JsonSerializer mySerializer = new JsonSerializer();
mySerializer.Serialize(myWriter, myList);
myWriter.Close();
return null;
}
You are doing _target.ToString() and since _target is of type targetResponse you get the default ToString text back, which is the full name of the object type.
You probably want to access a property of _target instead.

Parse JSON elegantly

I have a web api controller in .NET Core 2.1, which receives
JToken jsonBody
The json has the following structure
{
"id": "xxx",
"payload": {
"TelephoneNumber": "1111",
"Name": "Hans"
}
}
and more fields, but it's irrelevant.
I want to retrieve the Number and Name elegantly. Currently, I do the following, which I'm sure could be done in a nicer way:
var payload = JObject.Parse(jsonBody.SelectToken("Payload").ToString());
telephoneNumber = new TelephoneNumber(payload.SelectToken("TelephoneNumber").ToString());
I've tried just doing
jsonBody.SelectToken("Payload.TelephoneNumber")
but that doesn't work. I think that it's because somehow the jsonBody, that the controller receives, has only parsed the top nodes as json, hence it could be that it regards the value of
jsonBody.SelectToken("Payload")
as a string.
As per official documentation - you can do something like this:
var phone = jsonBody["payload"]["TelephoneNumber"].ToString();
var name = jsonBody["payload"]["Name"].ToString();
See a live demo on rextester.
This is at least a little bit more elegant:
var jsonBody = JObject.Parse(#"{
'id': 'xxx',
'payload': {
'TelephoneNumber': '1111',
'Name': 'Hans'
}
}");
var phone = jsonBody["payload"]["TelephoneNumber"].Value<string>();
var name = jsonBody["payload"]["Name"].Value<string>();
If you don't want to deserialize your full json, you can create a class with the properties you need
public class Payload
{
public string TelephoneNumber { get; set; }
public string Name { get; set; }
}
And then use JsonTextReader to deserialize the string:
private static Payload DeserializePayload(JToken token)
{
var serializer = new JsonSerializer();
using (JsonTextReader reader = new JsonTextReader(new StringReader(token.ToString())))
{
reader.CloseInput = true;
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject && reader.Path.Equals("payload"))
{
var payload = serializer.Deserialize<Payload>(reader);
return payload;
}
}
}
// not found - return null? throw exception?
return null;
}
Testing the code:
var token = JToken.Parse(#"{
""id"": ""xxx"",
""payload"": {
""TelephoneNumber"": ""1111"",
""Name"": ""Hans""
}
}");
Payload payload = DeserializePayload(token);
Console.WriteLine($"Name: {payload.Name}, Phone number: {payload.TelephoneNumber}");

JSON deserializeobject list of objects always null

I'm having an issue deserializing a JSON string into a RootObject class with 1 string property and a list of custom objects.
When I debug the application and the code deserializes the json I get my 'ErrorCode' property, "test", is populated in the RootObject class but the 'meets' property is always null.
The code sits in a cross platform Xamarin forms application currently, but I've pulled the code and class definitions out and ran them in a simple console application that worked first time with no issues. I'm struggling to figure out what I'm doing wrong.
My simple JSON object is the following:
{"meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
}
],
"ErrorCode": "test"}
My class definitions:
[JsonObject(Id = "Meets")]
public class Meets
{
[JsonProperty(PropertyName = "VenueName")]
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
The code to hit the api and get the json object (which is blanked out and a smaller simple object in its place):
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using EliteNfcBet.Models;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace EliteNfcBet.ViewModels
{
public class ItemsViewModel : BaseViewModel
{
public ObservableCollection<Meets> RaceMeets { get; set; }
public Command LoadItemsCommand { get; set; }
public ItemsViewModel ()
{
Title = "Select Meeting";
RaceMeets = new ObservableCollection<Meets>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
}
async Task ExecuteLoadItemsCommand()
{
if (IsBusy)
return;
IsBusy = true;
try
{
RaceMeets.Clear();
var result = await GetMeetingsAsync();
//RaceMeets = result;
//foreach (var meet in meets.Meets)
//{
// RaceMeets.Add(meet);
//}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public static async Task<RootObject> GetMeetingsAsync()
{
RootObject meet = new RootObject();
//List<Meet> meets = new List<Meet>();
HttpClient client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
var uri = new Uri(string.Format(Constants.RestUrl, string.Empty) + "/api/GetAvailablemeetings");
try
{
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
//var content = await response.Content.ReadAsStringAsync();
var content = "{\"meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}";
if (!string.IsNullOrEmpty(content))
{
ITraceWriter traceWriter = new MemoryTraceWriter();
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
},
TraceWriter = traceWriter
};
//result = JsonConvert.DeserializeObject<T>(json, settings);
meet = JsonConvert.DeserializeObject<RootObject>(content, settings);
Console.WriteLine(traceWriter);
}
//if (meets.Count > 0)
//{
// meet.MeetList = meets;
//}
}
}
catch (Exception ex)
{
meet.ErrorCode = "INTERNAL_ERROR";
}
return meet;
}
}
}
EDIT:
I've made some minor changes suggested which are below.
My Json string is now this:
"{\"Meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}"
My classes are below. One thing to note is they are defined within a 'models' namespace in a seperate code file that is doing the deserializing.
namespace EliteNfcBet.Models
{
public class Meets
{
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
}
Again i have debugging output when deserializing which looks like it points to the fact that the Meets class member not being found?
{2018-05-28T23:12:22.987 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets', line 1, position 9.
2018-05-28T23:12:22.993 Info Started deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 10.
2018-05-28T23:12:22.994 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0]', line 1, position 28.
2018-05-28T23:12:22.995 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.995 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.996 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1]', line 1, position 51.
2018-05-28T23:12:22.997 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2]', line 1, position 71.
2018-05-28T23:12:22.998 Info Finished deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 72.
2018-05-28T23:12:23.009 Info Finished deserializing EliteNfcBet.Models.RootObject. Path '', line 1, position 92.
2018-05-28T23:12:23.009 Verbose Deserialized JSON:
{
"Meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
}
],
"ErrorCode": "test"
}}
edit 3:
I've just came across this post which explains a lot! Seems like xamarin.forms has a known problem currently with reflection and so certain packages may not work correctly.
JsonConvert.SerializeObject always return {} in XamarinForms
Does anyone have any insight as to why this happens and when this will be resolved. Also a work around that I could implement so I can use debugging. Thanks.
{"meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
} ],
"ErrorCode": "test"}
Your problem is that you have an object called "meets" in javascript, and in your object in C# you have "Meets". Change it to "Meets" and it should work.
You also don't need the JsonObject attribute, I believe. .NET should be able to handle the serialization from JSON automatically:
public class Meets
{
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
Spend some time looking at these resources to understand why your error is occurring:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/
EDIT
The above classes produces the following json:
Meets:
{
"VenueName": null
}
Root Object:
{
"Meets": [
{
"VenueName": null
},
{
"VenueName": null
},
{
"VenueName": null
}
],
"ErrorCode": null
}

combine all json paths in string c#

i have a large json data and i want to get all paths from the root until getting value for the paths then storing the result to a string as i described bellow
here is my json for example
{
"root":{
"first":{
"first1":{
"value":"1"
},
"first2":{
"value":"2"
},
"first3":{
"value":"3"
}
},
"second":{
"second1":{
"value":"1"
},
"second2":{
"value":"2"
},
"second3":{
"value":"3"
}
},
"third":{
"third1":{
"value":"1"
},
"third2":{
"value":"2"
},
"third3":{
"value":"3"
}
},
"four":{
"value":"4"
},
"five":{
"five1":{
"five11":{
"value":"five11"
},
"five12":{
"value":"five12"
}
},
"five2":{
"five21":{
"five211":{
"value":"five211"
}
}
}
}
}
}
then i want to make each paths like bellow dynamically in c# and showing in screen please tell me a way to make this
root.first.first1.value
root.first.first2.value
root.first.first3.value
root.second.second1.value
......
root.four.value
root.five.five1.five11.value
root.five.five1.five12.value
....
root.five2.five21.five211.value
Use JSON.NET and iterate recursively through the Children property and check if the current token doesn't have HasValues set to true and if that's the case add the Path property of that token to a StringBuilder or what have you. Should give you exactly what you want.
Edith: Code Sample
I was lazy and just included the whole console application code.
Example on dotnetfiddle.net
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text;
public class Program
{
public static void Main()
{
var json = #"
{
""root"":{
""first"":{
""first1"":{
""value"":""1""
},
""first2"":{
""value"":""2""
},
""first3"":{
""value"":""3""
}
}
}
}";
var jobject = JObject.Parse (json);
var sb = new StringBuilder ();
RecursiveParse (sb, jobject);
Console.WriteLine (sb.ToString());
}
public static void RecursiveParse(StringBuilder sb, JToken token)
{
foreach (var item in token.Children()) {
if (item.HasValues)
{
RecursiveParse (sb, item);
} else {
sb.AppendLine (item.Path);
}
}
}
}

Categories