From an external webservice i receive either
// jsonWithConfig
// property config is an object {}
{"config":{"c1":"All","c2":"is peachy"},"message":"We found a config object"}
// jsonNoConfig
// property config is string with the value null
{"config":"null","message":"Config is null"}
I want to deserialize the json into these types
public class WebResponse
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Config Config { get; set; }
public string Message { get; set; }
// i also tried dynamic but
// a) this is not what i want
// b) it resulted in RuntimeBinderException
// public dynamic Config { get; set; }
}
public class Config
{
public string C1 { get; set; }
public string C2 { get; set; }
}
What have i tried?
From How to ignore properties with System.Text.Json i started with JsonSerializer.Deserialize from System.Text.Json
var options = new JsonSerializerOptions{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
string jsonWithConfig =
{"config":{"c1":"All","c2":"is peachy"},"message":"We found a Config"}
WebResponse webResponseWithConfig =
JsonSerializer.Deserialize<WebResponse>(jsonWithConfig, options);
This works for jsonWithConfig
which is no surprise since the json can be deserilized to the type WebResponse
.
What is the error?
I hoped that using JsonSerializerOptions.DefaultIgnoreCondition would work for jsonNoConfig = {"config":"null","message":"Config is null"}
.
But deserialization of jsonNoConfig
fails with DeserializeUnableToConvertValue
string jsonNoConfig =
{"config":"null","message":"Config is null"}
WebResponse webResponseNoConfig =
JsonSerializer.Deserialize<WebResponse>(jsonNoConfig, options);
Questions
- How can i deserialize
jsonNoConfig
? - What must i do?
Update
MySkullCaveIsADarkPlace pointed out that config
should have the value null
and not "null"
. After changing this the code above works as expected.
But is there a way to handle null with quotation marks like {"config":"null", ...}
as well?
Full stack trace
The stack trace inside linqpad shows this
at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type
propertyType)at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader&
reader, Type typeToConvert, JsonSerializerOptions options, ReadStack&
state, T& value)at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader&
reader, Type typeToConvert, JsonSerializerOptions options, ReadStack&
state, T& value)at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object
obj, ReadStack& state, Utf8JsonReader& reader)at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader&
reader, Type typeToConvert, JsonSerializerOptions options, ReadStack&
state, T& value)at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader&
reader, Type typeToConvert, JsonSerializerOptions options, ReadStack&
state, T& value)at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader&
reader, JsonSerializerOptions options, ReadStack& state)at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan
1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable
1 actualByteCount)at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1
json, JsonTypeInfo jsonTypeInfo)at System.Text.Json.JsonSerializer.Deserialize[TValue](String json,
JsonSerializerOptions options) at UserQuery.Main(), line 13
LINQPad program
This linqpad-program has all the code needed
// Linqpad program
void Main()
{
string jsonWithConfig = "{"config":{"c1":"All","c2":"is peachy"},"message":"We found a Config"}";
string jsonNoConfig = "{"config":"null","Message":"Config is null"}";
var options = new JsonSerializerOptions{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
WebResponse webResponseWithConfig = JsonSerializer.Deserialize<WebResponse>(jsonWithConfig, options);
webResponseWithConfig.Dump();
WebResponse webResponseNoConfig = JsonSerializer.Deserialize<WebResponse>(jsonNoConfig, options);
webResponseNoConfig.Dump();
}
// custom types
public class WebResponse
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Config Config { get; set; }
public string Message { get; set; }
}
public class Config
{
public string C1 { get; set; }
public string C2 { get; set; }
}
2
Answers
As explained in comments by MySkullCaveIsADarkPlace, your problem is that the JSON value
"null"
Is not null. It is a non-null string value containing the characters
null
. A null value looks like:For confirmation, see the original JSON proposal.
If you cannot fix the JSON to represent null values properly, you will need to write a custom JsonConverter that checks for a
"null"
text value and returnsnull
if present. If not present, the converter should proceed with default deserialization.The question How to use default serialization in a custom System.Text.Json JsonConverter? has this answer which provides a
DefaultConverterFactory<T>
. Grab it and subclass it as follows:NullTextValueForNullObjectConverter
DefaultConverterFactory
JsonSerializerExtensions
Then either add the converter to
JsonSerializerOptions.Converters
as follows:Or apply to the
Config
property directly as follows:Note that there does not appear to be a way currently to generate a default serialization of you apply the converter directly to the
Config
type. As such, I don’t recommend doing it.Demo fiddle here.
If you cannot fix the JSON source then in this particular case i would recommend to replace
"null"
withnull
using a c# string replace function