有没有更好的方法来处理Json.Net的编码值?

时间:2013-05-31 21:57:13

标签: c# json json.net

我正在使用Json.Net序列化/反序列化具有System.Text.Encoding类型属性的类。尝试一个简单的测试,我的班级序列化没有任何问题:

public class TestClass {
    public Encoding TheEncoding { get; set; }
}

var testClass = new TestClass { TheEncoding = Encoding.UTF8 };
var json = JsonConvert.SerializeObject( testClass, Formatting.Indented );
var obj = JsonConvert.DeserializeObject<TestClass>( json );

序列化为:

{
  "TheEncoding": {
    "BodyName": "utf-8",
    "EncodingName": "Unicode (UTF-8)",
    "HeaderName": "utf-8",
    "WebName": "utf-8",
    "WindowsCodePage": 1200,
    "IsBrowserDisplay": true,
    "IsBrowserSave": true,
    "IsMailNewsDisplay": true,
    "IsMailNewsSave": true,
    "IsSingleByte": false,
    "EncoderFallback": {
      "DefaultString": "?",
      "MaxCharCount": 1
    },
    "DecoderFallback": {
      "DefaultString": "?",
      "MaxCharCount": 1
    },
    "IsReadOnly": true,
    "CodePage": 65001
  }
}

然而,在反序列化时,我得到了一个例外:

  

无法创建System.Text.Encoding类型的实例。类型是   接口或抽象类,无法实例化。路径   'TheEncoding.BodyName',第3行,第16位。

我能够通过创建处理System.Text.Encoding类型的自定义转换器来解决此问题:

public class JsonEncodingConverter : JsonConverter {
    public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) {
        // Serialize as the BodyName.
        serializer.Serialize( writer, ( value as Encoding ).BodyName );
    }

    public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) {
        // Already good to go.
        return existingValue;
    }

    public override bool CanConvert( Type objectType ) {
        return ( typeof ( Encoding ).IsAssignableFrom( objectType ) );
    }
}

var testClass = new TestClass { TheEncoding = Encoding.UTF8 };
var json = JsonConvert.SerializeObject( testClass, Formatting.Indented, new JsonEncodingConverter() );
var obj = JsonConvert.DeserializeObject<TestClass>( json , new JsonEncodingConverter() );

使用自定义转换器进行序列化现在可以生成:

{
  "TheEncoding": "utf-8"
}

使用自定义转换器进行反序列化时,此JSON可以成功地往返回原始对象。

我是Json.Net的新手,我有一种强烈的感觉,我正在努力做到这一点!当然,处理System.Text.Encoding会有更好的,更少参与的方式吗?

2 个答案:

答案 0 :(得分:2)

使用[DataContract][DataMember]属性明确设置将在TestClass个对象上序列化哪些属性。

  1. 忽略[DataMember]媒体资源中的TheEncoding属性。
  2. 创建一个辅助属性,将其序列化为“utf-8”(取决于TheEncoding的值)。在此媒体资源上添加[DataMember]属性。
  3. 例如:

    [DataContract]
    public class TestClass
    {
      public Encoding TheEncoding { get; set; }
    
      [DataMember]
      public string TheEncodingName
      {
        get
        {
          if (this.TheEncoding == System.Text.Encoding.UTF8)
            return "utf-8";
          // TODO: More possibilities
        }
        set
        {
          if (value == "utf-8")
            this.TheEncoding = System.Text.Encoding.UTF8;
          // TODO: More possibilities
        }
      }
    }
    

    序列化后,系统会跳过TheEncoding,而TheEncodingName会被序列化。

答案 1 :(得分:0)

我认为解决这个问题的更好方法是弄清楚你在JSON对象上需要什么属性?

服务器端没有理由包含Encoding对象中的所有属性,因为您已经在运行时作为.NET框架的一部分访问它。

在客户端上,我无法想象你为什么需要Encoding对象的所有属性。

发送EncodingNameBodyName可能更直观,您可以从中确定要在服务器上使用的编码对象。

例如,如果我要向服务器发送一些指定utf-8的JSON,我会知道使用Encoding.UTF8