-1

I have the following class to serialize

class Container
{
    [JsonConverter(typeof(PropertyConverter))]
    public PropertyBase SomeProperty { get; set; }
}

Which is serialized with

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
}:

var serialized = JsonConvert.SerializeObject(
    new Container
    {
        SomeProperty = new PropertyImplementationA
        {
            PropertyA = "some string value"
        }
    }, settings);

but when I deserialize with

var deserialized = JsonConvert.DeserializeObject<Container>(settings);

The converter is not used.

On investigation, if I remove the sname case naming strategy it all works so it appears that Newtonsoft is registering the the converter to the property name with a different naming strategy when using the JsonConverterAttibute.

Constraints

As a workaround one can register the converters with the serializer settings I won't always know the converters to be used when the settings are created, that isn't a feasable option for this case.

As another workaround one can decorate the properties with [JsonProperty("property_base")] explicitly but this also isn't feasable as we would need to decorate properties all over the codebase.

This works as expected if one doesn't specify the SnameCaseNamingStrategy however this strategy is what the codebase already uses and can't be changed.

Question

How does one get the JsonConverterAttribute to use the same naming strategy as the JsonSerializerSettings passed to the JsonConvert.DeserializeObject function?

You can run a working example in .Net Fiddle here

Jay
  • 3,373
  • 6
  • 38
  • 55

1 Answers1

2

It seems that ContractResolver gives a priority to a JsonConverter. I think maybe it is a good idea otherwise it would be hard to predict a result. If you move a contract resolver into a JsonConverter or add the property names explicitly everyting is ok

class Container
{
    [JsonConverter(typeof(PropertyConverter))]
    [JsonProperty("some_property")]
    public PropertyBase SomeProperty { get; set; }
}
class PropertyImplementationA : PropertyBase
{
    override public string Type => nameof(PropertyImplementationA);
    [JsonProperty("property_a")]
    public string PropertyA { get; set; }
}

Everything is working fine when I added contract resolver settings inside of the json converter. In this case you don't need JsonProperty attributes. I also made the converter much more simple

override public PropertyBase? ReadJson(JsonReader reader, Type objectType, PropertyBase? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
        if (reader.TokenType == JsonToken.Null) return null;
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver
            {
                NamingStrategy = new SnakeCaseNamingStrategy()
            }
        };
var jObject = JObject.Load(reader);
return (PropertyBase)JsonConvert.DeserializeObject(jObject.ToString(), 
Type.GetType((string)jObject["type"]),settings);
}

and classes could be much more simple too

class PropertyImplementationA : PropertyBase
{
    public string PropertyA { get; set; }
}

abstract class PropertyBase
{
    public string Type
    {
        get { return this.GetType().Name; }
    }
}

and even more simple , you can use SerializeTypeNameHandling option of Newtonsoft.Json https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

Serge
  • 40,935
  • 4
  • 18
  • 45
  • Thanks for the response. Yes the issue is that the properties aren't being registered with the correct casing so I'd like to know how to do so without having to hardcode each property name. Surely there must be some way to achieve this as Newtonsoft just needs to register the converter to the snake cased property name. This all works in ASP.NET if one does `services.AddNewtonsoftJson(o => o.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() });` – Jay Mar 09 '23 at 16:17
  • @Jay I think this question is out of the scope. You have to email it to James Newton-King. I just can offer you a workaround. – Serge Mar 09 '23 at 16:22
  • @Jay And see my update. I moved settings inside of the converter. Now you don't neeed JsonProperty attributes – Serge Mar 09 '23 at 16:55
  • Thanks @Serge. Based on your responses I think my question was a bit too open ended. It took a while to find better wording so thanks for bearing through that. – Jay Mar 10 '23 at 11:28