System.Text.Json.JsonSerializer を使用して datetime 値を逆シリアル化するときに、値が期待される形式でない場合、JsonException がスローされます。日時が ISO-8601-1:2019 形式であることが想定されています (例:2021-07-12T12:35:34+00:00)。
たとえば、次のコードは、datetime 値を予期しない形式で逆シリアル化しようとしています:
var eventJson = "{\"HappenedAt\":\"2021-05-26 18:30:41.720\", \"Name\":\"Meltdown\"}";
var sysEvent = JsonSerializer.Deserialize<SystemEvent>(eventJson);
Code language: C# (cs)
これにより、次の例外がスローされます:
日時形式をそのまま使用して JSON を逆シリアル化する必要がある (そして変更できない) と仮定すると、解決策はカスタム コンバーターを作成して使用することです。その方法を以下に示します。
注:この問題は、DateTime、DateTime?、DateTimeOffset、および DateTimeOffset? で発生し、解決策はこれらすべてのケースでほぼ同じです。
解決策 – カスタム日時コンバーターを使用する
次の手順は、使用している形式で datetime 値を逆シリアル化するカスタム コンバーターを作成する方法を示しています。
ステップ 1 – JsonConverter のサブクラス化
カスタム日時コンバーターを作成するには、次のように JsonConverter をサブクラス化します。
using System.Text.Json;
using System.Text.Json.Serialization;
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
//Don't implement this unless you're going to use the custom converter for serialization too
throw new NotImplementedException();
}
}
Code language: C# (cs)
ステップ 2 – Read() を実装する
逆シリアル化をカスタマイズしたいので、Read() を実装する必要があります。 Write() を実装する必要はありません (シリアル化にカスタム コンバーターも使用する場合を除きます)。
たとえば、正確な形式のみを解析できるようにする場合は、DateTime.ParseExact() を使用できます。
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd H:mm:ss.fff", null);
}
Code language: C# (cs)
DateTime.Parse() は、この記事で使用されている日時 (2021-05-26 18:30:41.720) でも機能します:
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.Parse(reader.GetString());
}
Code language: C# (cs)
DateTime.Parse() はさまざまな形式を解析できるため、注意して使用してください。非常に特殊な形式のみを受け入れたい場合は、代わりに ParseExact() を使用してください。
ステップ 3 – カスタム コンバーターを JsonSerializer に渡す
カスタム コンバーターを使用するには、それを JsonSerializerOptions.Converters に追加し、次のようにオプションを JsonSerializer.Deserialize() に渡します。
var eventJson = "{\"HappenedAt\":\"2021-05-26 18:30:41.720\", \"Name\":\"Meltdown\"}";
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomDateTimeConverter());
var sysEvent = JsonSerializer.Deserialize<SystemEvent>(eventJson, options);
Code language: C# (cs)
JsonSerializer が HappenedAt プロパティに到達すると、カスタム コンバーターが呼び出され、datetime 値が正常に解析されます。