Json.Net - 从“System.Net.IPAddress"上的“ScopeId"获取值时出错 [英] Json.Net - Error getting value from 'ScopeId' on 'System.Net.IPAddress'

查看:17
本文介绍了Json.Net - 从“System.Net.IPAddress"上的“ScopeId"获取值时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Json.Net 序列化 IPEndpoint 对象,但出现以下错误:

I am trying to serialize an IPEndpoint object with Json.Net and I get the following error:

从System.Net.IPAddress"上的ScopeId"获取值时出错.

Error getting value from 'ScopeId' on 'System.Net.IPAddress'.

错误的原因是我只使用端点中 IPAddress 对象的 IPV4 属性.当 Json 解析器尝试解析 IPv6 部分时,它会访问 ScopeID 属性,该属性会引发套接字异常所引用的对象类型不支持尝试的操作"(Microsoft 的 null 就足够了!)

The cause of the error is that I am only using the IPV4 properties of the IPAddress object in the endpoint. When the Json parser tries to parse the IPv6 portion, it accesses the ScopeID property which throws a socket exception "The attempted operation is not supported for the type of object referenced" (A null would have sufficed microsoft!)

我想知道除了将所有内容撕开并将地址信息编码为字符串之外,是否还有其他解决方法?在某些时候,我确实想支持 IPV6.如果 IPAddress 系列设置为 Internetwork 而不是 InternetworkIPV6,是否可以在 Json.NET 中执行任何操作来忽略错误或干脆不尝试序列化 ScopeID?

I was wondering if there may be a workaround for this other than ripping everything apart and coding the address information as a string? At some point I do want to support IPV6. Is there anything that can be done in Json.NET to ignore the error or simply NOT attempt to serialize the ScopeID if the IPAddress family is set to Internetwork instead of InternetworkIPV6?

谢谢,

丁斯代尔

推荐答案

如您所见,IPAddress 类对序列化不是很友好.如果您尝试访问 IPv4 地址的 ScopeID 字段,它不仅会抛出 SocketException,而且如果您尝试访问 Address<,它也会抛出/code> 字段直接用于 IPv6 地址.

The IPAddress class is not very friendly to serialization, as you've seen. Not only will it throw a SocketException if you try to access the ScopeID field for an IPv4 address, but it will also throw if you try to access the Address field directly for an IPv6 address.

要绕过异常,您需要一个自定义 JsonConverter.转换器允许您准确地告诉 Json.Net 您希望它如何序列化和/或反序列化特定类型的对象.对于一个IPAddress,似乎最简单的方法来获得满足每个人的数据只是将其转换为它的字符串表示并返回.我们可以在转换器中做到这一点.这是我的写法:

To get around the exceptions, you will need a custom JsonConverter. A converter allows you to tell Json.Net exactly how you'd like it to serialize and/or deserialize a particular type of object. For an IPAddress, it seems the easiest way to get the data that satisfies everyone is simply to convert it to its string representation and back. We can do that in the converter. Here is how I would write it:

class IPAddressConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IPAddress));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return IPAddress.Parse((string)reader.Value);
    }
}

很简单,就像这些事情一样.但是,这并不是故事的结局.如果您需要使用 IPEndPoint 进行往返,那么您也需要一个转换器.为什么?因为 IPEndPoint 不包含默认构造函数,所以 Json.Net 将不知道如何实例化它.幸运的是,这个转换器也不难写:

Pretty straightforward, as these things go. But, this is not the end of the story. If you need to go round-trip with your IPEndPoint, then you will need a converter for it as well. Why? Because IPEndPoint does not contain a default constructor, so Json.Net will not know how to instantiate it. Fortunately, this converter is not difficult to write either:

class IPEndPointConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IPEndPoint));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        IPEndPoint ep = (IPEndPoint)value;
        JObject jo = new JObject();
        jo.Add("Address", JToken.FromObject(ep.Address, serializer));
        jo.Add("Port", ep.Port);
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        IPAddress address = jo["Address"].ToObject<IPAddress>(serializer);
        int port = (int)jo["Port"];
        return new IPEndPoint(address, port);
    }
}

那么,既然我们有了转换器,我们该如何使用它们呢?这是一个演示的简单示例程序.它首先创建几个端点,使用自定义转换器将它们序列化为 JSON,然后立即使用相同的转换器再次将 JSON 反序列化回端点.

So, now that we have the converters, how do we use them? Here is a simple example program that demonstrates. It first creates a couple of endpoints, serializes them to JSON using the custom converters, then immediately deserializes the JSON back into endpoints again using the same converters.

public class Program
{
    static void Main(string[] args)
    {
        var endpoints = new IPEndPoint[]
        {
            new IPEndPoint(IPAddress.Parse("8.8.4.4"), 53),
            new IPEndPoint(IPAddress.Parse("2001:db8::ff00:42:8329"), 81)
        };

        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new IPAddressConverter());
        settings.Converters.Add(new IPEndPointConverter());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(endpoints, settings);
        Console.WriteLine(json);

        var endpoints2 = JsonConvert.DeserializeObject<IPEndPoint[]>(json, settings);

        foreach (IPEndPoint ep in endpoints2)
        {
            Console.WriteLine();
            Console.WriteLine("AddressFamily: " + ep.AddressFamily);
            Console.WriteLine("Address: " + ep.Address);
            Console.WriteLine("Port: " + ep.Port);
        }
    }
}

这是输出:

[
  {
    "Address": "8.8.4.4",
    "Port": 53
  },
  {
    "Address": "2001:db8::ff00:42:8329",
    "Port": 81
  }
]

AddressFamily: InterNetwork
Address: 8.8.4.4
Port: 53

AddressFamily: InterNetworkV6
Address: 2001:db8::ff00:42:8329
Port: 81

小提琴:https://dotnetfiddle.net/tK7NKY

这篇关于Json.Net - 从“System.Net.IPAddress"上的“ScopeId"获取值时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆