Klasa IPAddress
nie jest bardzo przyjazny dla serializacji, jak widzieliście. Nie tylko rzuci SocketException
, jeśli spróbujesz uzyskać dostęp do pola ScopeID
dla adresu IPv4, ale będzie również rzutować, jeśli spróbujesz uzyskać dostęp do pola Address
bezpośrednio dla adresu IPv6.
Aby obejść wyjątki, potrzebny będzie niestandardowy JsonConverter
. Konwerter pozwala ci powiedzieć Json.Net dokładnie, jak chcesz, aby serializować i/lub deserializować konkretny typ obiektu. Dla modelu IPAddress
wydaje się, że najłatwiejszym sposobem uzyskania danych, które zadowolą wszystkich, jest po prostu przekształcenie go w jego reprezentację ciągów i powrót. Możemy to zrobić w konwerterze. Oto, jak to napisać:
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);
}
}
Dość proste, jak te rzeczy. Ale to nie koniec historii. Jeśli chcesz jeździć w obie strony razem z urządzeniem IPEndPoint
, potrzebujesz również konwertera. Czemu? Ponieważ IPEndPoint
nie zawiera domyślnego konstruktora, więc Json.Net nie będzie wiedział, jak go utworzyć. Na szczęście ten konwerter również nie jest trudny do napisania:
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);
}
}
Więc, skoro mamy konwertery, jak ich używamy? Oto prosty przykładowy program, który pokazuje. Najpierw tworzy kilka punktów końcowych, serializuje je do JSON-a za pomocą niestandardowych konwerterów, a następnie ponownie deserializuje JSON z powrotem do punktów końcowych ponownie, używając tych samych konwerterów.
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);
}
}
}
Oto wynik:
[
{
"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
Kodeks 'WriteJson' można uprościć używając' JObject' też. – Athari
Brilliant. Dziękuję bardzo Brian! – Dinsdale
Bez problemu; miło, że mogłem pomóc. –