First off, I had a hard time with the title of this one; I'll edit it if I get any better suggestions.
I have a json string that looks like this
{
"chapters": [
{
"id": 0,
"tags": {
"title": "Chapter 1"
}
},
{
"id": 1,
"tags": {
"title": "Chapter 2"
}
}
]
}
My model for this is as such
public class Chapter
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("tags")]
public ChapterTags Tags { get; set; }
[JsonIgnore]
public string Title
{
get { return Tags.Title; }
set { if (Tags.Title != value) Tags.Title = value; }
}
}
public class ChapterTags
{
[JsonPropertyName("title")]
public string Title { get; set; }
}
and here is the code I'm using to deserialize the json
var jsonTask = GetJsonAsync();
using var jsonResults = JsonDocument.Parse(await jsonTask);
var jsonChapters = jsonResults.RootElement.GetProperty("chapters");
List<Chapter> chapters = JsonSerializer.Deserialize<List<Chapter>>(jsonChapters) ?? new();
I want to get rid of the Tags
property and the ChapterTags
class and just be left with
public class Chapter
{
[JsonPropertyName("id")]
public int Id { get; set; }
public string Title {get; set;}
}
as a simple single class model.
My only thought was to use a JsonConverter but could not figure out how to make that work. I can't change the format of the json input because it is being generated by an outside source.
Also, if it matters, I will never have to re-serialize the object back to json.
I am using VS2022 Preview, as that is currently the only way to work with .Net Maui.
CodePudding user response:
try this
List<Chapter> chapters = JsonDocument.Parse(json)
.RootElement.GetProperty("chapters")
.EnumerateArray()
.Select(c => new Chapter
{
Id = Convert.ToInt32(c.GetProperty("id").ToString()),
Title = c.GetProperty("tags").GetProperty("title").ToString()
})
.ToList();
CodePudding user response:
I ended up going the converter route.
Recap of input JSON
{
"chapters": [
{
"id": 0,
"tags": {
"title": "Chapter 1"
}
},
{
"id": 1,
"tags": {
"title": "Chapter 2"
}
}
]
}
My converter class
public class JsonChapterTitleConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var jsonTags = JsonDocument.ParseValue(ref reader);
var jsonTitle = jsonTags.RootElement.GetProperty("title");
return jsonTitle.GetString();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => throw new NotImplementedException();
}
New model
public class Chapter
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("tags")]
[JsonConverter(typeof(JsonChapterTitleConverter))]
public string Title { get; set; }
}
The code used to deserialize the JSON is unchanged
I like the answer Serge gave. In this case however, I feel like it violates the Open-Closed Principle (if I understand it correctly). The JSON shown is not the full string; only what is important to me at the moment. If I decide I need to deserialize more of the elements; not only would I have to extend my model, but also modify the deserialization method in my service class. Using the converter means I only have to add another property to my model corresponding to the JSON property I want to capture.
While Maksym's answer isn't a complete answer, the link provided gave me the boost I needed to figure this out.
Thank you.
Comments welcome.
CodePudding user response:
I believe this question should help you Custom Deserialization using Json.NET
You are right JsonConverter is something needed here.