1

In a project targeting .NET 6 I have some properties of type DateOnly.

I receive my data in JSON format via POST request through a web API.

However, since the Newtonsoft JsonSerializer currently does not support the deserialization of DateOnly fields I implemented 2 custom converters for DateOnly and DateOnly? (the pretty much look the same as the one mentioned here Newtonsoft DateOnly support issue on GitHub.

Now I want to uses those converters wherever needed in my web api project, so I installed the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet package and added the following code to my ServiceCollectionExtension:

services.AddControllers()
        .AddNewtonsoftJson(options => 
        {
            options.SerializerSettings.Converters.Add(new DateOnlyConverter());
            options.SerializerSettings.Converters.Add(new NullableDateOnlyConverter());
        });

Now when I try to send some data to the API I still get a Newtonsoft.Json.JsonSerilizationException because the JsonSerializer does not now how to convert the value to a DateOnly type.

It only works if I specify the JsonSerializerSettings right before the invocation of JsonConvert.DeserializeObject(), add the converters to the collection of converters and then pass the settings as an argument to the method call.

What am I missing?

Edit:

For further information this is the result of exception.ToString():

Newtonsoft.Json.JsonSerializationException: 
Error converting value "2021-12-22" to type 'System.DateOnly'. Path 'MyNamespace.MyObject', line 3, position 30.
 ---> System.ArgumentException: Could not cast or convert from System.String to System.DateOnly.
   at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
   at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)

   --- End of inner exception stack trace ---

   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at SomeNamespace.MyController.DeserializeMyObject(String someJsonForMyObject) in MyDrive:\MyUser\SomePath\MyController.cs:line 78
dbc
  • 91,441
  • 18
  • 186
  • 284
FFranz
  • 78
  • 1
  • 10
  • Do the converters get triggered at all? You can check this e.g. by putting a Breakpoint inside them. – Peter B Dec 21 '21 at 11:00
  • Not when only added through the `ServiceCollectionExtension`. Like I said they only get triggered when I create the `SerializerSettings` before calling `DeserializeObject` and pass the settings as an argument. Then they do would they're supposed to do and everythings works perfectly fine. But I want to use them everywhere in my project, so creating a new instance of `JsonSerializerSettings` before each call to any `JsonConvert` method would be a bad approach. – FFranz Dec 21 '21 at 11:06
  • 1
    Where is the `JsonSerilizationException` getting thrown? Can you [edit] your question to share the full `ToString()` output of the exception including the exception type, message, traceback and inner exception(s), if any? – dbc Dec 21 '21 at 16:17
  • @dbc Sure, I'll add the requested information in a few minutes. Please excuse my late response. – FFranz Dec 22 '21 at 10:13
  • 1
    `options.SerializerSettings` only sets the serializer settings **used by the ASP.NET Framework**. That has no effect on direct calls to Newtonsoft made in applications code, which is what you seem to be doing here. To set settings globally for direct calls see [Json.net global settings](https://stackoverflow.com/q/15066904/3744182), which looks to be a duplicate. Agree? – dbc Dec 22 '21 at 14:08
  • 1
    @dbc Didn't try it out yet but looks pretty much like the same issue. Thanks for your help, I wonder why I didn't find it. Sorry for the duplicate! Happy Holidays! :) – FFranz Dec 22 '21 at 22:57

0 Answers0