Dot-Net

Json.net 鬆散與嚴格類型反序列化

  • November 9, 2012

在我正在進行的項目中,我們開始使用 Json.Net 庫。

但是,我剛剛發現 json.net 在字元串類型上是“鬆散的”。

這是一個例子:

DTO 類

[JsonObject]
public class DTO
{
   [JsonProperty]
   public string type;
}

反序列化

byte[] rawBody = GetBytes(@"{""type"":true}");
using (MemoryStream ms = new MemoryStream(rawBody))
{
   using (StreamReader sr = new StreamReader(ms))
   {
       var serializer = new JsonSerializer();

       return serializer.Deserialize(sr, typeof(DTO));
    }
}

這會將“type”屬性反序列化為“True”。但是,我希望它會失敗並拋出異常,因為存在類型不匹配。如果我在 json 中將 true 替換為 1,它的作用相同。屬性“類型”的值為“1”。

問題:

  1. 有沒有辦法強制執行嚴格的序列化?
  2. 除了字元串之外,還有其他類型像我們在這裡看到的那樣具有隱式轉換嗎?

謝謝你。

傑夫

我想出了一個解決方法。

雖然它有效,但我不知道這是否是解決我的“問題”的好方法。

我使用轉換器從

這是我所做的:

[JsonObject]
public class DTO
{
   [JsonProperty]
   public string type;
}

自定義轉換器:

class JsonStrictConverter<T> : JsonConverter
   {
       public JsonToken[] TokenTypes { get; set; }

       public JsonStrictConverter(params JsonToken[] tokenTypes)
       {
           TokenTypes = tokenTypes;
       }

       public override bool CanConvert(Type objectType)
       {
           return objectType == typeof(T);
       }
       public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
       {
           if (reader.TokenType == JsonToken.Null)
           {
               if (objectType.IsValueType)
               {
                   return Activator.CreateInstance(objectType);
               }
               return null;
           }

           var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
           return (T)converter.ConvertFromString(reader.Value.ToString());
       }
       public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
       {
           throw new NotImplementedException("The converter '" + this.GetType().Name + "' is not intended to be used when serializing.");
       }
       public override bool CanWrite { get { return false; } }
   }

反序列化:

XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
bodyReader.ReadStartElement("Binary");
byte[] rawBody = bodyReader.ReadContentAsBase64();
using (MemoryStream ms = new MemoryStream(rawBody))
{
   using (StreamReader sr = new StreamReader(ms))
   {
       var serializer = new JsonSerializer();
       /* These converter are present to enforce strict data type in the json. */ 
       /* by default, newtonsoft can serialize Numbers as strings, strings as boolean, etc.... */
       serializer.Converters.Add(new JsonStrictConverter<string>(JsonToken.String));
       serializer.Converters.Add(new JsonStrictConverter<bool>(JsonToken.Boolean));
       serializer.Converters.Add(new JsonStrictConverter<short>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<ushort>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<int>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<uint>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<long>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<ulong>(JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<float>(JsonToken.Float, JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<double>(JsonToken.Float, JsonToken.Integer));
       serializer.Converters.Add(new JsonStrictConverter<decimal>(JsonToken.Float, JsonToken.Integer));

       return serializer.Deserialize(sr, typeof(DTO));                    
   }
}

這種方法中是否缺少任何類型?

周圍有沒有更好的解決方案?

謝謝你。

引用自:https://stackoverflow.com/questions/13273033