JSON.Net and ASP.NET: Can I set NullValueHandling to Ignore globally, for deserialization only?

.NET Framework WebApi application with hundreds of endpoints handling messages of hundreds of different types. I want to ignore, suppress, or otherwise obviate any JsonSerializationException emitted by JSON.Net because an object argument was deserialized from a message that contained a null value for a non-nullable property.

I COULD globally set GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.NullValueHandling to NullValueHandling.Ignore. This does the trick. But I don’t want to do this, because it also changes the behavior when these API endpoints serialize their responses, and I don’t want to affect any client behavior or cause other downstream issues; if an endpoint is returning serialized objects with null properties included, they must continue to do so.

Can I set NullValueHandling just for deserialization only? Or, I also fiddled with a custom JsonConverter that would handle every single deserialization in the entire application; that was a bust, but maybe there’s something in that vein?

  • I should add that I am aware that I could go find every potential source of this issue – every property of every message type used in the application – and ensure that the non-nullable properties have default values. But that’s not a tenable strategy because I would go crazy before I finished.

    – 

  • What version specifically of WebApi are you using? Depending on the version you may be able to use a custom model binder.

    – 




  • Microsoft.AspNet.WebApi.Core 5.3.0

    – 

I circled back to the idea of a custom JsonConverter applied globally via
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new JsonCreationNullValueIgnoringConverter())

This may do the trick but needs extensive testing:

public class JsonCreationNullValueIgnoringConverter : JsonConverter
{
    // do not allow serialization with this converter
    public override bool CanWrite {  get { return false; } }
    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    // override deserialization to force NullValueHandling to Ignore
    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        serializer.NullValueHandling = NullValueHandling.Ignore;
        serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        // this causes a stack overflow for some reason:
        // return serializer.Deserialize(reader, objectType);

        // Load JObject from stream 
        JObject jObject = JObject.Load(reader);

        // Create target object
        object target = Activator.CreateInstance(objectType);

        // Populate the object properties 
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
    // only deserialize models from our assembly,
    // except any enumerations as those can be converted by the default converter
    public override bool CanConvert(Type objectType)
    {
        return objectType.Assembly.Equals(typeof(My.Assembly.SomeArbitraryModel).Assembly) && !objectType.IsEnum;
    }
}

Leave a Comment