Die IPAddress
Klasse ist nicht sehr freundlich zu Serialisierung, wie Sie gesehen haben. Wenn Sie versuchen, auf das Feld ScopeID
für eine IPv4-Adresse zuzugreifen, wird es nicht nur SocketException
werfen, sondern es wird auch ausgelöst, wenn Sie versuchen, auf das Feld Address
direkt für eine IPv6-Adresse zuzugreifen.
Um die Ausnahmen zu umgehen, benötigen Sie eine benutzerdefinierte JsonConverter
. Mit einem Konverter können Sie Json.Net genau sagen, wie Sie einen bestimmten Objekttyp serialisieren und/oder deserialisieren möchten. Für einen scheint es der einfachste Weg zu sein, die Daten, die alle befriedigen, einfach in ihre Zeichenfolgendarstellung und zurück zu konvertieren. Das können wir im Konverter machen. Hier ist, wie ich es schreiben würde:
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);
}
}
Ziemlich einfach, wie diese Dinge gehen. Aber das ist nicht das Ende der Geschichte. Wenn Sie mit Ihrer IPEndPoint
eine Hin- und Rückfahrt machen müssen, benötigen Sie auch einen Konverter. Warum? Da IPEndPoint
keinen Standardkonstruktor enthält, wird Json.Net nicht wissen, wie es instanziiert wird. Glücklicherweise ist dieser Konverter auch nicht schwer zu schreiben:
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);
}
}
Also, jetzt, wo wir die Konverter haben, wie benutzen wir sie? Hier ist ein einfaches Beispielprogramm, das demonstriert. Es erstellt zunächst ein paar Endpunkte, serialisiert sie JSON die benutzerdefinierten Konvertern, dann sofort deserialisiert die JSON zurück in Endpunkte wieder die gleichen Wandler verwenden. Hier
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);
}
}
}
ist die Ausgabe:
[
{
"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
Fiddle: https://dotnetfiddle.net/tK7NKY
Code of 'WriteJson' vereinfacht werden kann' JObject' zu verwenden. – Athari
Brilliant. Vielen Dank Brian! – Dinsdale
Kein Problem; froh, dass ich Helfen kann. –