Writing a custom deserializer in .NET 5
One of the things I miss from my XAML development days are the converters. A converter was just what the name says, a class that converts a property to something that you can show in your UI. For example, maybe you had a timestamp in your model and instead of showing 1616623541 in your UI, you could convert it to "25th of March 2021". Today I learned that I can do something like this in my dotnet controllers using custom de/serializers.
Let's say you have the following requirement for an endpoint:
- receive an image encoded in base64 along with other information, as a JSON payload
- convert the base64 image to bytes in order to save it or send it somewhere else
Usually, you would make a class that looks like the one below and you would convert the base64 string to an array of bytes.
public class UploadImageModel
{
public string Image { get; set; }
public string SomeOtherProperty { get; set; }
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] UploadImageModel model)
{
byte[] imageBytes = Convert.FromBase64String(model.Image);
// now do something with the bytes array
await _myOtherAPI.UploadImageBytes(imageBytes);
}
With a custom deserializer you don't have to do this manually because you can just add an attribute to any property from your model, and it will be done automatically:
public class UploadImageModel
{
[JsonConverter(typeof(Base64FileJsonConverter))]
public byte[] Image { get; set; }
public string SomeOtherProperty { get; set; }
}
public class Base64FileJsonConverter : JsonConverter<byte[]>
{
public override byte[] Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
return reader.GetBytesFromBase64();
}
public override void Write(Utf8JsonWriter writer, byte[] wf, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] UploadImageModel model)
{
// now we use our Image property directly
await _myOtherAPI.UploadImageBytes(model.Image);
}
Notice that now we have a byte[] Image property instead of a string, and the Base64FileJsonConverter converter is converting the base64 string into a byte array. That byte array will be assigned to our Image property so we don't have to make the conversion in our controller.
I also made a small repo where you can play with the code. It has a simple controller where you can POST a JSON with a base64 encoded image and it will return the image back. Enjoy!