System.Text.Json.JsonException:Der JSON-Wert konnte nicht in System.DateTime konvertiert werden

System.Text.Json.JsonException:Der JSON-Wert konnte nicht in System.DateTime konvertiert werden

Wenn beim Deserialisieren eines datetime-Werts mit System.Text.Json.JsonSerializer der Wert nicht das erwartete Format hat, wird eine JsonException ausgelöst. Es erwartet Datetimes im Format ISO-8601-1:2019 (z. B.:2021-07-12T12:35:34+00:00).

Der folgende Code versucht beispielsweise, einen datetime-Wert in einem unerwarteten Format zu deserialisieren:

var eventJson = "{\"HappenedAt\":\"2021-05-26 18:30:41.720\", \"Name\":\"Meltdown\"}";
var sysEvent = JsonSerializer.Deserialize<SystemEvent>(eventJson);
Code language: C# (cs)

Dadurch wird die folgende Ausnahme ausgelöst:

Angenommen, Sie müssen JSON mit dem Datetime-Format unverändert deserialisieren (und können es nicht ändern), dann besteht die Lösung darin, einen benutzerdefinierten Konverter zu erstellen und zu verwenden. Wie das geht, zeige ich weiter unten.

Hinweis:Dieses Problem tritt bei DateTime, DateTime?, DateTimeOffset und DateTimeOffset? auf, und die Lösung ist für alle diese Fälle nahezu gleich.

Lösung – Verwenden Sie einen benutzerdefinierten Datetime-Konverter

Die folgenden Schritte zeigen, wie Sie einen benutzerdefinierten Konverter erstellen, der einen datetime-Wert mit dem von Ihnen verwendeten Format deserialisiert.

Schritt 1 – Unterklasse JsonConverter

Um einen benutzerdefinierten Datetime-Konverter zu erstellen, leiten Sie JsonConverter wie folgt ab:

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)

Schritt 2 – Implementieren Sie Read()

Da Sie die Deserialisierung anpassen möchten, müssen Sie Read() implementieren. Sie müssen Write() nicht implementieren (es sei denn, Sie verwenden auch den benutzerdefinierten Konverter für die Serialisierung).

Beispielsweise können Sie DateTime.ParseExact() verwenden, wenn Sie nur Ihr genaues Format parsen möchten:

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() würde auch mit der in diesem Artikel verwendeten Datumszeit (2021-05-26 18:30:41.720) funktionieren:

public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
	return DateTime.Parse(reader.GetString());
}
Code language: C# (cs)

Seien Sie vorsichtig bei der Verwendung von DateTime.Parse(), da es eine Vielzahl von Formaten analysieren kann. Wenn Sie nur ein ganz bestimmtes Format akzeptieren möchten, verwenden Sie stattdessen ParseExact().

Schritt 3 – Übergeben Sie den benutzerdefinierten Konverter an JsonSerializer

Um den benutzerdefinierten Konverter zu verwenden, fügen Sie ihn zu JsonSerializerOptions.Converters hinzu und übergeben Sie dann die Optionen wie folgt an 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)

Wenn JsonSerializer auf die HappenedAt-Eigenschaft stößt, ruft es den benutzerdefinierten Konverter auf, der den datetime-Wert erfolgreich parst.