Json.Net – 从’System.Net.IPAddress’上的’ScopeId’获取值时出错

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

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

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

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

谢谢,

Dinsdale

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

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

 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(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(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