Json Convert empty string instead of null
@Kirill Shlenskiy's solution is great, but it does not take the NullValueHandling
attribute in consideration.
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Remark{ get; set; }
Here is an improved version that will take care of it. If NullValueHandling.Ignore
is set and the value is null, it will be skipped in the JSON output.
public sealed class SubstituteNullWithEmptyStringContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(string))
{
// Wrap value provider supplied by Json.NET.
property.ValueProvider = new NullToEmptyStringValueProvider(property.ValueProvider, property.NullValueHandling);
}
return property;
}
sealed class NullToEmptyStringValueProvider : IValueProvider
{
private readonly IValueProvider Provider;
private readonly NullValueHandling? NullHandling;
public NullToEmptyStringValueProvider(IValueProvider provider, NullValueHandling? nullValueHandling)
{
Provider = provider ?? throw new ArgumentNullException("provider");
NullHandling = nullValueHandling;
}
public object GetValue(object target)
{
if (NullHandling.HasValue
&& NullHandling.Value == NullValueHandling.Ignore
&& Provider.GetValue(target) == null )
{
return null;
}
return Provider.GetValue(target) ?? "";
}
public void SetValue(object target, object value)
{
Provider.SetValue(target, value);
}
}
}
While the accepted answer pointed me in the right direction, it appears quite brittle. I do not want to worry about resolving the list of JsonProperty
objects and implementing IValueResolver
myself when there are perfectly functional tools available for doing that in Json.NET (which could have all kinds of optimizations and corner case handling built in that a basic reflection-based reimplementation won't).
My solution performs minimal overriding and resolver substitution to ensure that only parts that absolutely need to change are actually altered:
public sealed class SubstituteNullWithEmptyStringContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(string))
{
// Wrap value provider supplied by Json.NET.
property.ValueProvider = new NullToEmptyStringValueProvider(property.ValueProvider);
}
return property;
}
sealed class NullToEmptyStringValueProvider : IValueProvider
{
private readonly IValueProvider Provider;
public NullToEmptyStringValueProvider(IValueProvider provider)
{
if (provider == null) throw new ArgumentNullException("provider");
Provider = provider;
}
public object GetValue(object target)
{
return Provider.GetValue(target) ?? "";
}
public void SetValue(object target, object value)
{
Provider.SetValue(target, value);
}
}
}
This should work:
var settings = new JsonSerializerSettings() { ContractResolver= new NullToEmptyStringResolver() };
var str = JsonConvert.SerializeObject(yourObj, settings);
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
public class NullToEmptyStringResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return type.GetProperties()
.Select(p=>{
var jp = base.CreateProperty(p, memberSerialization);
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
return jp;
}).ToList();
}
}
public class NullToEmptyStringValueProvider : IValueProvider
{
PropertyInfo _MemberInfo;
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
{
_MemberInfo = memberInfo;
}
public object GetValue(object target)
{
object result = _MemberInfo.GetValue(target);
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
return result;
}
public void SetValue(object target, object value)
{
_MemberInfo.SetValue(target, value);
}
}
Well, my solution pretty simple, but does not use JSON.NET features, just add backend field to your property:
public class Test
{
private string _myProperty = string.Empty;
[JsonProperty(PropertyName = "myProperty")]
public string MyProperty
{
get { return _myProperty; }
set { _myProperty = value; }
}
}
Edit:
In c# 6.0 property initialization will be available:
public class Test
{
[JsonProperty(PropertyName = "myProperty")]
public string MyProperty { get; set;} = "";
}