Json.NET Uri(de)序列化错误

时间:2011-10-17 10:23:15

标签: serialization deserialization json.net

我需要使用最新的(4.0.3)Json.NET库序列化和反序列化包含System.Uri属性的对象。

以下代码演示了此问题:

string input = "http://test.com/%22foo+bar%22";
Uri uri = new Uri(input);
string json = JsonConvert.SerializeObject(uri);
Uri output = JsonConvert.DeserializeObject<Uri>(json);

DeserializeObject方法抛出JsonReaderException。这适用于4.0.2。

我已经在codeplex上提交了一个问题,其中包含测试和修补程序以解决问题,但似乎作者需要花一点时间来发布固定版本。

同时有什么我可以做的(使用JsonSettings或其他任何东西)使最新版本按预期工作?

到目前为止我有几个选择:

  1. 坚持4.0.2 - 新的nuget包取决于4.0.3
  2. 将uri更改为字符串 - 我宁愿使用选项1并手动管理pkg依赖项
  3. 使用带补丁的自定义构建 - 这就是我现在正在做的事情,但我讨厌覆盖nuget软件包的程序集。

1 个答案:

答案 0 :(得分:4)

您可以使用System.Uri属性编写一个绕过Uri.OriginalString常规处理的辅助类,并将其纯粹视为字符串。

这是一个代码示例,它与从Json.Net的JsonConverter派生的转换器类完全相同。

OriginalString Property (System.Uri) @ MSDN

有一点需要注意,您必须更新使用JsonConvert的所有位置,以将辅助类作为额外的JsonConverter参数之一包含在内。

我还在类中添加了一个使用Uri作为成员变量的示例,以证明一个人不一定要覆盖类的属性,尽管它可能对您更方便。如果是这样,您可以使用[JsonConverter(UriConverter)]作为需要它的成员的属性。

using Newtonsoft.Json;

namespace JsonUriSerializeTest
{
    class Program
    {
        public class UriConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return objectType.Equals(typeof(Uri));
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                if (reader.TokenType == JsonToken.String)
                {
                    return new Uri((string)reader.Value);
                }

                if (reader.TokenType == JsonToken.Null)
                {
                    return null;
                }

                throw new InvalidOperationException("Unhandled case for UriConverter. Check to see if this converter has been applied to the wrong serialization type.");
            }

            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                if (null == value)
                {
                    writer.WriteNull();
                    return;
                }

                if (value is Uri)
                {
                    writer.WriteValue(((Uri)value).OriginalString);
                    return;
                }

                throw new InvalidOperationException("Unhandled case for UriConverter. Check to see if this converter has been applied to the wrong serialization type.");
            }
        }

        public class UriPair
        {
            public string label { get; set; }
            public Uri first { get; set; }
            public Uri second { get; set; }

            public void Display()
            {
                Console.WriteLine(string.Format("label:  {0}", label));
                Console.WriteLine(string.Format("first:  {0}", first));
                Console.WriteLine(string.Format("second: {0}", second));
            }
        }

        static void Main(string[] args)
        {
            string input = "http://test.com/%22foo+bar%22";
            Uri uri = new Uri(input);
            string json = JsonConvert.SerializeObject(uri, new UriConverter());
            Uri output = JsonConvert.DeserializeObject<Uri>(json, new UriConverter());

            Console.WriteLine(input);
            Console.WriteLine(output.ToString());
            Console.WriteLine();

            UriPair pair = new UriPair();
            pair.label = input;
            pair.first = null;
            pair.second = new Uri(input);
            string jsonPair = JsonConvert.SerializeObject(pair, new UriConverter());
            UriPair outputPair = JsonConvert.DeserializeObject<UriPair>(jsonPair, new UriConverter());

            outputPair.Display();
            Console.WriteLine();

            Console.ReadKey();
        }
    }
}