繁体   English   中英

Json.Net - 从'System.Net.IPAddress'上的'ScopeId'获取值时出错

[英]Json.Net - Error getting value from 'ScopeId' on 'System.Net.IPAddress'

我试图用Json.Net序列化IPEndpoint对象,我收到以下错误:

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

导致错误的原因是我只使用端点中IPAddress对象的IPV4属性。 当Json解析器尝试解析IPv6部分时,它会访问ScopeID属性,该属性会抛出套接字异常“对于引用的对象类型,不支持尝试的操作”(null将足以支持microsoft!)

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

谢谢,

Dinsdale

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

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

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 ,那么你也需要一个转换器。 为什么? 因为IPEndPoint不包含默认构造函数,所以Json.Net将不知道如何实例化它。 幸运的是,这个转换器也不难写:

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重新反序列化为端点。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM