.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 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;
}
}
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