使用Json.Net将空字符串转换为null [英] Convert empty strings to null with Json.Net

查看:254
本文介绍了使用Json.Net将空字符串转换为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在寻找一种方法来自动将所有EmptyOrWhiteSpace字符串自动反序列化(服务器端)到null时遇到麻烦.默认情况下,Json.Net只是将值分配给object属性,我需要逐个字符串地验证它是空还是空白,然后将其设置为null.

我需要在反序列化时完成此操作,因此我不必记住验证来自客户端的每个字符串.

如何在Json Net上覆盖它?

解决方案

经过大量源代码挖掘,我解决了我的问题. 事实证明,只有在我反序列化包含字符串属性的复杂对象时,注释中提出的所有解决方案才有效. 在这种情况下,是的,只需修改合同解析器即可[1].

但是,我需要的是一种在反序列化时将任何字符串转换为null的方法,并且在我的对象只是一个字符串的情况下,以这种方式修改合同将失败,即

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

发生的事情是,当我们使用复杂的对象时,JSON.NET在内部将JsonToken.StartObjectTokenType分配给读取器,这将导致反序列化遵循某个调用property.ValueProvider.SetValue(target, value);的特定路径. /p>

但是,如果对象只是一个字符串,则TokenType将是JsonToken.String,并且路径将是不同的,并且值提供程序将永远不会被调用.

无论如何,我的解决方案是建立一个自定义转换器,以转换具有TokenType == JsonToken.StringJsonReader(下面的代码).

解决方案

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]归功于@RaphaëlAlthaus.

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

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 JsonReaders 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);
    }
}

这篇关于使用Json.Net将空字符串转换为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆