Currently I have JSON that either comes in via an HTTP call or is stored in a database but during server processing they are mapped to C# objects.
These objects have properties like public List<int> MyArray.
When the JSON contains MyArray:null I want the resulting property to be an empty List<T> instead of a null List<T> property.
The goal is that the object will "reserialize" to JSON as MyArray:[], thus either saving to the database or responding out via HTTP as an empty array instead of null.
That way, no matter what, the C# class is basically scrubbing and enforcing an empty array for any List<T> property that would otherwise be null and cause things to break in the browser side code (for example: cannot read property 'length' of null).
Is there a way that during the serialization/deserialization I can have any null value that is paired to a List<T> property become an empty array instead?
I was going to suggest using a custom JsonConverter to solve this, but a converter will not get called for null values.  Instead, you will need to use a custom IContractResolver in combination with a custom IValueProvider.  Here is the code you would need (inspired by this answer):
class NullToEmptyListResolver : DefaultContractResolver
{
    protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
    {
        IValueProvider provider = base.CreateMemberValueProvider(member);
        if (member.MemberType == MemberTypes.Property)
        {
            Type propType = ((PropertyInfo)member).PropertyType;
            if (propType.IsGenericType && 
                propType.GetGenericTypeDefinition() == typeof(List<>))
            {
                return new EmptyListValueProvider(provider, propType);
            }
        }
        return provider;
    }
    class EmptyListValueProvider : IValueProvider
    {
        private IValueProvider innerProvider;
        private object defaultValue;
        public EmptyListValueProvider(IValueProvider innerProvider, Type listType)
        {
            this.innerProvider = innerProvider;
            defaultValue = Activator.CreateInstance(listType);
        }
        public void SetValue(object target, object value)
        {
            innerProvider.SetValue(target, value ?? defaultValue);
        }
        public object GetValue(object target)
        {
            return innerProvider.GetValue(target) ?? defaultValue;
        }
    }
}
Here is a demo which shows how to use the resolver:
class Program
{
    static void Main(string[] args)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.ContractResolver = new NullToEmptyListResolver();
        settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
        settings.Formatting = Formatting.Indented;
        Console.WriteLine("Serializing object with null lists...");
        Foo foo = new Foo();
        string json = JsonConvert.SerializeObject(foo, settings);
        Console.WriteLine(json);
        Console.WriteLine();
        Console.WriteLine("Deserializing JSON with null lists...");
        json = @"{ ""IntList"" : null, ""StringList"" : null }";
        foo = JsonConvert.DeserializeObject<Foo>(json, settings);
        Console.WriteLine("IntList size: " + foo.IntList.Count);
        Console.WriteLine("StringList size: " + foo.StringList.Count);
    }
}
class Foo
{
    public List<int> IntList { get; set; }
    public List<string> StringList { get; set; }
}
Output:
Serializing object with null lists...
{
  "IntList": [],
  "StringList": []
}
Deserializing JSON with null lists...
IntList size: 0
StringList size: 0
                        You could always lazy load an empty list if its null.
OR
Use the NullValueHandling option on the JsonDeserializer.
var settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
return JsonConvert.DeserializeObject<T>(json, settings);
http://james.newtonking.com/json/help/index.html?topic=html/SerializationSettings.htm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With