This is apparently a known restriction of System.Text.Json
. See the issues:
Thus (in .Net 5 at least) you will need to refactor your class to avoid the limitation.
One solution would be to add a surrogate Base64 encoded string property:
public class AvatarImage
{
[JsonIgnore]
public Byte[] Data { get; set; } = null;
[JsonInclude]
[JsonPropertyName("Data")]
public string Base64Data
{
private get => Data == null ? null : Convert.ToBase64String(Data);
set
{
var index = value.IndexOf(',');
this.Data = Convert.FromBase64String(index < 0 ? value : value.Remove(0, index + 1));
}
}
}
Note that, ordinarily, JsonSerializer
will only serialize public properties. However, if you mark a property with [JsonInclude]
then either the setter or the getter -- but not both -- can be nonpublic. (I have no idea why Microsoft doesn't allow both to be private, the data contract serializers certainly support private members marked with [DataMember]
.) In this case I chose to make the getter private to reduce the chance the surrogate property is serialized by some other serializer or displayed via some property browser.
Demo fiddle #1 here.
Alternatively, you could introduce a custom JsonConverter<T>
for AvatarImage
[JsonConverter(typeof(AvatarConverter))]
public class AvatarImage
{
public Byte[] Data { get; set; } = null;
}
class AvatarConverter : JsonConverter<AvatarImage>
{
class AvatarDTO { public string Data { get; set; } }
public override AvatarImage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dto = JsonSerializer.Deserialize<AvatarDTO>(ref reader, options);
var index = dto.Data?.IndexOf(',') ?? -1;
return new AvatarImage { Data = dto.Data == null ? null : Convert.FromBase64String(index < 0 ? dto.Data : dto.Data.Remove(0, index + 1)) };
}
public override void Write(Utf8JsonWriter writer, AvatarImage value, JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, new { Data = value.Data }, options);
}
This seems to be the easier solution if for simple models, but can become a nuisance for complex models or models to which properties are frequently added.
Demo fiddle #2 here.
Finally, it seems a bit unfortunate that the Data
property will have some extra header prepended during deserialization that is not present during serialization. Rather than fixing this during deserialization, consider modifying your architecture to avoid mangling the Data
string in the first place.