見てきたように、このIPAddress
クラスはシリアル化にあまり適していません。IPv4 アドレスSocketException
のフィールドにアクセスしようとするとスローされるだけでなく、IPv6 アドレスのフィールドに直接アクセスしようとするとスローされます。 ScopeID
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