I'm having trouble finding a way to automatically deserialize (server side) all EmptyOrWhiteSpace
strings to null
. Json.Net by default simply assigns the value to the object property, and I need to verify string by string whether it is empty or white space, and then set it to null.
I need this to be done upon deserialization, so I don't have to remember to verify every single string that comes from the client.
How can I override this on Json Net?
After a lot of source digging, I solved my problem. Turns out all the solutions proposed in the comments only work if I am deserializing a complex object which contains a property that is a string. In this case, yes, simply modifying the contract resolver works [1].
However, what I needed was a way to convert any string to null upon deserialization, and modifying the contract this way will fail for the case where my object is just a string, i.e.,
public void MyMethod(string jsonSomeInfo)
{
// At this point, jsonSomeInfo is "\"\"",
// an emmpty string.
var deserialized = new JsonSerializer().Deserialize(new StringReader(jsonSomeInfo), typeof(string));
// deserialized = "", event if I used the modified contract resolver [1].
}
What happens is that when we work with a complex object, internally JSON.NET assigns a TokenType
of JsonToken.StartObject
to the reader, which will cause the deserialization to follow a certain path where property.ValueProvider.SetValue(target, value);
is called.
However, if the object is just a string, the TokenType
will be JsonToken.String
, and the path will be different, and the value provider will never be invoked.
In any event, my solution was to build a custom converter to convert JsonReader
s that have TokenType == JsonToken.String
(code below).
Solution
public class StringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null) return null;
string text = reader.Value.ToString();
if (string.IsNullOrWhiteSpace(text))
{
return null;
}
return text;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("Not needed because this converter cannot write json");
}
public override bool CanWrite
{
get { return false; }
}
}
[1] Credits to @Raphaël Althaus.
public class NullToEmptyStringResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return type.GetProperties()
.Select(p => {
var jp = base.CreateProperty(p, memberSerialization);
jp.ValueProvider = new EmptyToNullStringValueProvider(p);
return jp;
}).ToList();
}
}
public class EmptyToNullStringValueProvider : IValueProvider
{
PropertyInfo _MemberInfo;
public EmptyToNullStringValueProvider(PropertyInfo memberInfo)
{
_MemberInfo = memberInfo;
}
public object GetValue(object target)
{
object result = _MemberInfo.GetValue(target);
if (_MemberInfo.PropertyType == typeof(string) && result != null && string.IsNullOrWhiteSpace(result.ToString()))
{
result = null;
}
return result;
}
public void SetValue(object target, object value)
{
if (_MemberInfo.PropertyType == typeof(string) && value != null && string.IsNullOrWhiteSpace(value.ToString()))
{
value = null;
}
_MemberInfo.SetValue(target, value);
}
}
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