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

wlzqhblo  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(138)

我试图用Json.Net序列化IPEndpoint对象,得到以下错误:
System.Net.IPAddress上的ScopeId获取值时出错。
错误的原因是我只在端点中使用了IPAddress对象的IPV4属性。当Json解析器尝试解析IPv6部分时,它访问ScopeID属性,从而引发套接字异常
引用的对象类型不支持尝试的操作”(microsoft!)
我想知道是否有一个解决办法,除了撕裂所有东西和编码地址信息为字符串?在某种程度上,我想支持IPV6。如果IPAddress系列设置为Internetwork而不是InternetworkIPV6,那么在Json.NET中有什么可以忽略错误或者干脆不尝试序列化ScopeID吗?

hm2xizp9

hm2xizp91#

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不包含默认构造函数,所以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

相关问题