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

发布于 2024-12-10 00:08:58 字数 733 浏览 1 评论 0原文

我需要使用最新的 (4.0.3) Json.NET 图书馆。

以下代码演示了该问题:

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 包的程序集的想法。

I need to serialize and deserialize an object that contains an System.Uri property using the latest (4.0.3) Json.NET library.

The following code demonstrates the problem:

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

The DeserializeObject method throws an JsonReaderException. This works fine with 4.0.2.

I've submitted an issue on codeplex with tests and patch to fix the issue, but it seems it takes a bit for the author to release a fixed version.

Meanwhile is there anything i can do ( using JsonSettings or anything else ) to make the latest version work as expected?

A few options i have so far:

  1. stick to 4.0.2 - new nuget packages depend on 4.0.3
  2. change uri to string - i rather go with option 1 and manually managed pkg dependencies
  3. use custom build with patch applied - this is what i'm doing now but i hate the idea of overriding the nuget package's assemblies.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南街女流氓 2024-12-17 00:08:58

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

下面的代码示例使用从 Json.Net 的 JsonConverter 派生的转换器类来执行此操作。

OriginalString 属性 (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();
        }
    }
}

You can write a helper class that circumvents the usual handling of System.Uri and treats it purely as a string, using the Uri.OriginalString property.

Here's a code sample that does exactly that with a converter class derived from Json.Net's JsonConverter.

OriginalString Property (System.Uri) @ MSDN

One caveat is that you must update all places where you use JsonConvert to include the helper class as one of the extra JsonConverter parameters.

I've also added an example using Uri as a member variable in a class, to demonstrate that one wouldn't necessarily have to override the attributes on a class, though it might be more convenient for you. If so, you could use [JsonConverter(UriConverter)] as an attribute on members that need it.

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文