Json.Net - получение значения ошибки от 'Кодобласти' на 'системы.Чистая.IP-адрес'

Я пытаюсь сериализовать объект IPEndpoint с помощью Json.Net и я получаю следующую ошибку:

ошибка получения значения из системы "ScopeId" on.Сеть.IPAddress'.

причиной ошибки является то, что я использую только свойства IPV4 объекта IPAddress в конечной точке. Когда анализатор Json пытается проанализировать часть IPv6, он обращается к свойству ScopeID, которое создает исключение сокета "попытка операции не поддерживается для типа объекта referenced "(a null было бы достаточно microsoft!)

Мне было интересно, может ли быть обходной путь для этого, кроме разрыва всего и кодирования адресной информации в виде строки? В какой-то момент я хочу поддерживать IPV6. Есть ли что-нибудь, что можно сделать в Json.NET игнорировать ошибку или просто не пытаться сериализовать ScopeID, если семейство IPAddress установлено в Internetwork вместо InternetworkIPV6?

спасибо,

Динсдейл

1 ответов


на IPAddress класс не очень дружелюбный к сериализации, как вы видели. Мало того, что он бросит SocketException если вы попытаетесь получить доступ к ScopeID поле для адреса IPv4, но он также будет бросать, если вы попытаетесь получить доступ к Address поле непосредственно для адреса IPv6.

чтобы обойти исключения, вам понадобится пользовательский 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