How to avoid JSON deserialisation issues with .NET 6 Web APIs

Published on
Reading time
Authors

It's been a while since I've coded more than a few lines of C# and in that time Microsoft has gone from .NET Core 3.1 to .NET 5 and now 6.

I am currently working on an IoT gateway project and I thought I would use the new minimal APIs in .NET 6 to build the API for the gateway. The gateway accepts a POST from a device which contains JSON in the body. I wanted to serialise this into a C# object so I could do some gateway processing before sending the data upstream to Azure.

The problem

As a long-time .NET user I immediately reached for JSON.net (aka Newtonsoft.Json) and imported the nuget package into my project. I had a sample of the device JSON and utilised a VS Code extension to create a C# class based on the JSON document.

I updated one backing property to be more readable (SensorName) and left the JsonProperty to match the incoming document property (Geo) I wanted mapped to this field.

////////
// Incorrect sample
////////
using Newtonsoft.Json;

public class SensorData
{
  [JsonProperty("SensorId")]
  public string SensorId { get; set; }

  [JsonProperty("DateTime")]
  public string DateTime { get; set; }

  [JsonProperty("Geo")]
  public string SensorName { get; set; }
}

Job almost done I thought!

I headed over to my Controller class in my ASP.NET Web API and created the method to accept the POST and data.

[HttpPost\]
public async Task<string> Post(SensorData data)
{
   // Do some work return "OK";
}

Now that the code was ready for testing I ran the code in the debugger and pushed a test call to this API endpoint and immediately received this response:

The field SensorName is required.

Wait, this is the backing field and not the JSON property - this isn't the response I was expecting! I also noticed that other fields held their default values (such as 0 for an int). Not great!

I spent quite some time hunting down the cause and it looks like this is due to the .NET shift towards using it's own in-built JSON libraries, the reasons for which are documented from the original launch in 2019.

The fix

It turns out that the fix is to forget the Newtonsoft.Json library completely and rely only on System.Text.Json instead. You'll notice that the property attribute is also named differently (JsonPropertyName), so you need to update that as well.

////////
// Correct sample
////////
using using System.Text.Json.Serialization;

public class SensorData
{
  [JsonPropertyName("SensorId")]
  public string SensorId { get; set; }

  [JsonPropertyName("DateTime")]
  public string DateTime { get; set; }

  [JsonPropertyName("Geo")]
  public string SensorName { get; set; }
}

After making this change the deserialisation of the request body worked as expected and all fields were populated and I was on my merry way.

I thought I'd post here in case anyone else comes across this issue because there was no 'aha' moment on Stack Overflow or elsewhere, so I hope this is yours!

Happy days! 😎