Reputation: 645
So it seems like the new Json library doesn't deserialize ( or even serialize for that matter) the UInt32
types. In an MVC application the following is sent in the payload of a POST:
{
"Overrides":{
},
"Directions":{
"data1" : "data2"
},
"ModeId": "1782354543",
"TestNumber" : 10
}
And the class it should be serialized to is like this:
public class Payload
{
public uint ModeId;
public Dictionary<string, string> Directions{ get; set; } = new();
public Dictionary<string, string> Overrides { get; set; } = new();
public int TestNumber { get; set; }
}
But when the request is received, ModeId
is 0. I tried adding a custom converter based on the unit tests I found here
Like so:
public class UIntConverter : JsonConverter<uint>
{
public override uint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
string stringValue = reader.GetString();
if (uint.TryParse(stringValue, out uint x))
{
return x;
}
}
if (reader.TokenType == JsonTokenType.Number)
{
return reader.GetUInt32();
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, uint value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value);
}
}
And registering it like this:
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.IgnoreNullValues = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.Converters.Insert(options.JsonSerializerOptions.Converters.Count,new UIntConverter());
});
I even failed to serialize my class into string using the same converter. It just ignores the uid property.
var payload = new Payload()
{
Directions = new Directions
{
{"data1", "data2" }
},
ModeId = 1782354543,
TestNumber = 10
}
//then try to serialize
var defaultJsonSerializerSettings = new JsonSerializerOptions()
{
IgnoreNullValues = true,
WriteIndented = false,
PropertyNamingPolicy = null,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
Converters = { new UIntConverter()}
};
Serializer.Serialize(payload, typeof(Payload), defaultJsonSerializerSettings);
It serializes everything, except the uint property which is ignored altogether.
What do you suggest/advise for the serialization/deserialization of a uint property?
[UPDATE] : The issue was the fact that I was trying to serialize/deserialize a field as opposed to a property with public accessors as is pointed out in the answers. It just so happened that field was of type uint
.
Upvotes: 1
Views: 2068
Reputation: 35075
If you're on .NET 5, or if - as @Jimi pointed out - install <PackageReference Include="System.Text.Json" Version="5.0.2" />
, you can then use IncludeFields
and AllowReadingFromString
options:
var serializeOptions = new JsonSerializerOptions
{
IncludeFields = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
var p = JsonSerializer.Deserialize<Payload>(json, serializeOptions);
Before .NET5 you'll need to change ModeId to be a property.
BTW. You could deal with string/int with no converter:
public string ModeId {get; set}
public uint ModeIdParsed => uint.Parse(ModeId);
If you need to keep ModeId
name then you could
public class Payload
{
[JsonPropertyName("ModeId")]
public string modeId {get;set;}
[JsonIgnore]
public uint ModeId => uint.Parse(modeId);
}
Unfortunately in 3.1 you'll need to keep the string variant public (deserializing privates is available from v5).
Upvotes: 3