Json.net将所有空字符串反序列化为null

时间:2018-06-21 18:33:02

标签: c# json json.net

我有一个端点,即使类型完全不同,它也会以空字符串的形式返回所有空值。例如,该数据

[{
    "field1": 3,
    "field2": "bob",
    "field3": ["alpha", "beta", "gamma"],
    "field4": { "some": "data" }
},
{
    "field1": "", // needs to be deserialized as null
    "field2": "", // same
    "field3": "", // ..
    "field4": "" // ..
}]

需要序列化为以下模型(的一个数组):

public class Root
{
    public int? Field1 { get; set; }
    public string Field2 { get; set; }
    public string[] Field3 { get; set; }
    public JObject Field4 { get; set; }
}

但是Json.Net抛出异常:

Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Error setting value to 'Field4' on 'Root'. ---> System.InvalidCastException: Unable to cast object of type 'Newtonsoft.Json.Linq.JValue' to type 'Newtonsoft.Json.Linq.JObject'.

我尝试使用Contracts,ValueProviders和Converters时遇到了麻烦。我该怎么做呢?

这些链接都没有对我有帮助:
Customize Json.NET serialization to consider empty strings as null
Convert empty strings to null with Json.Net
Json Convert empty string instead of null

EDIT1:固定错字。

EDIT2:这是我尝试使用的转换器的代码:

public class VdfNullConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // ...
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.String && (reader.Value as string == ""))
            return null;

        // I don't know what to do here
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

我的问题是,我不知道该如何处理数据实际上不是空字符串的情况。在那种情况下,我需要调用其他转换器,但无法通过ReadJson进行“取消”。

2 个答案:

答案 0 :(得分:0)

如果模型确实仅包含4个字段,则可以考虑使用序列化属性

public class Root{

  [JsonIgnore]
  public int? Field1 {get;set;}

  [JsonProperty("field1")]
  protected string Field1Data{
     {
        get { return Field1?.ToString(); }
        set { 
           if (string.IsNullOrEmpty(value))
              Field1 = null;
           else {
              int parsed;
              if (Int32.TryParse(value, out parsed)){
                 Field1 = parsed;
              } else {
                 throw new ArgumentException($"{value} could not be parsed", nameof(Field1));
              }
           }
        } 
     }
  } 
}

如果模型的类型和字段种类繁多,则必须使用custom json converter

无论哪种方式,示例中的JObject都可疑。它可能需要为其他类型,例如Object。

编辑:

由于类型繁多,因此您可能需要考虑在反序列化json之前对其进行预处理,因为使用转换器会要求更高的特异性。

您可以将输入解析为JObject,选择所有空字符串值并删除属性:

  var jobj = JObject.Parse(File.ReadAllText("sample.json"));
  var tokens = jobj.SelectTokens("$..[?(@=~/^$/)]").ToList();
  tokens.ForEach(t=>t.Parent.Remove()); // you could filter some of the removals if you need to 
  string nowUseThisAsYourImpup = jobj.ToString();  

答案 1 :(得分:0)

我终于找到了一个简单但棘手的解决方案。我使用了常规的JsonConverter并使用如下代码回溯:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.String && (reader.Value as string == ""))
        return null;

    skip = true;
    return serializer.Deserialize(reader, objectType);
}

private bool skip = false;
public override bool CanConvert(Type objectType) // If this is ever cached, this hack won't work.
{
    if (skip)
    {
        skip = false;
        return false;
    }

    return true;
}