I'm trying to use the System.Text.Json.JsonSerializer
to deserialize the model partially, so one of the properties is read as string that contains the original JSON.
public class SomeModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Info { get; set; }
}
The example code
var json = @"{
""Id"": 1,
""Name"": ""Some Name"",
""Info"": {
""Additional"": ""Fields"",
""Are"": ""Inside""
}
}";
var model = JsonSerializer.Deserialize<SomeModel>(json);
should produce the model, which Info
property contains the Info object from the original JSON as string:
{
"Additional": "Fields",
"Are": "Inside"
}
It doesn't work out of the box and throws an exception:
System.Text.Json.JsonException: ---> System.InvalidOperationException: Cannot get the value of a token type 'StartObject' as a string.
What have I tried so far:
public class InfoToStringConverter : JsonConverter<string>
{
public override string Read(
ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
{
return reader.GetString();
}
public override void Write(
Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
and apply it in the model as
[JsonConverter(typeof(InfoToStringConverter))]
public string Info { get; set; }
and add in the options to JsonSerializer
var options = new JsonSerializerOptions();
options.Converters.Add(new InfoToStringConverter());
var model = JsonSerializer.Deserialize<SomeModel>(json, options);
Still, it throws the same exception:
System.Text.Json.JsonException: ---> System.InvalidOperationException: Cannot get the value of a token type 'StartObject' as a string.
What is the right recipe to cook what I need? It worked in a similar way using Newtonsoft.Json
.
Update
For me it is important to keep the nested JSON object as original as possible. So, I'd avoid options like to deserialize as Dictionary
and serialize back, because I'm afraid to introduce undesirable changes.
Found a right way how to correctly read the nested JSON object inside the JsonConverter
. The complete solution is the following:
public class SomeModel
{
public int Id { get; set; }
public string Name { get; set; }
[JsonConverter(typeof(InfoToStringConverter))]
public string Info { get; set; }
}
public class InfoToStringConverter : JsonConverter<string>
{
public override string Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
return jsonDoc.RootElement.GetRawText();
}
}
public override void Write(
Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
In the code itself there is no need even to create options:
var json = @"{
""Id"": 1,
""Name"": ""Some Name"",
""Info"": {
""Additional"": ""Fields"",
""Are"": ""Inside""
}
}";
var model = JsonSerializer.Deserialize<SomeModel>(json);
The raw JSON text in the Info
property contains even extra spaces introduced in the example for nice readability.
And there is no mixing of model representation and its serialization as remarked @PavelAnikhouski in his answer.