Newtonsoft is known for their JSON library. Very useful and used everywhere, even for serialization of complex object in REST, NServicebus, …
But in some specific cases, the behavior of this serializer / deserializer can be weird.
My case here is about passing a String containing a DateTime, like: “2023-10-03T10:00:00Z”. Which is a UTC DateTime for the 3rd of October 2023 at 10 o’clock.
What I receive on the other side is still a String, but it has been transformed to this “10/03/2023 10:00”. Which is completely wrong because: first the month and day have been inverted, we lost the UTC format and simply because the string is not the one I’ve sent…
In the case of a WebAPI on REST it actually works fine, even if the String is contained in a complex object. But if you had the following attribute:
[JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
Code language: C# (cs)
Then you have the issue.
The solution in this case was to create a custom converter than implements JsonConverter:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyNameSpace;
public class StringDateTimeJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MyDtoObject);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//This is to avoid the Newtonsoft serializer and deserializer to parse a string to a dateTime automatically
var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
var jsonText = JObject.Load(reader).ToString();
var jsonObject = (JObject)JsonConvert.DeserializeObject(jsonText, settings);
var result = new MyDtoObject{ Value = (string)jsonObject["value"] };
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
Code language: C# (cs)
Here MyDtoObject has the custom attribute and contains a String called Value (observe that the name when serialized becomes “value”). So to avoid the deserializer to do the conversion, you need to specify that it should not do the automatic handling of the date by using: DateParseHandling.None.
This solves our issue for REST once you change the attribute with:
[JsonConverter(typeof(StringDateTimeJsonConverter), "discriminator")]
Code language: C# (cs)
Now, what about NServiceBus?
You probably have a class managing the EndpointConfiguration. Something like:
var endpointConfiguration = new EndpointConfiguration("queueName");
...
endpointConfiguration.AddDeserializer<NewtonsoftJsonSerializer>();
Code language: C# (cs)
The idea is the same as before, which is to configure how the serializer / deserializer is supposed to behave if it detects a DateTime in a String:
//This is to avoid the Newtonsoft serializer and deserializer to parse a string to a dateTime automatically
var jsonSerializerSettings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
SerializationExtensions<NewtonsoftJsonSerializer>? deserializer = endpointConfiguration.AddDeserializer<NewtonsoftJsonSerializer>();
deserializer.Settings(jsonSerializerSettings);
Code language: C# (cs)
Problem solved! 🙂