System.Text.Json.JsonException:el valor JSON no se pudo convertir a System.DateTime

System.Text.Json.JsonException:el valor JSON no se pudo convertir a System.DateTime

Al deserializar un valor de fecha y hora con System.Text.Json.JsonSerializer, si el valor no tiene el formato esperado, generará una excepción JsonException. Espera que las fechas y horas tengan el formato ISO-8601-1:2019 (por ejemplo:2021-07-12T12:35:34+00:00).

Por ejemplo, el siguiente código intenta deserializar un valor de fecha y hora en un formato inesperado:

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

Esto generará la siguiente excepción:

Suponiendo que debe deserializar el JSON con el formato de fecha y hora tal cual (y no puede cambiarlo), la solución es crear y usar un convertidor personalizado. Mostraré cómo hacerlo a continuación.

Nota:Este problema ocurre para DateTime, DateTime?, DateTimeOffset y DateTimeOffset?, y la solución es casi la misma para todos estos casos.

Solución:utilice un convertidor de fecha y hora personalizado

Los siguientes pasos muestran cómo crear un convertidor personalizado que deserializa un valor de fecha y hora con cualquier formato que esté usando.

Paso 1:subclase JsonConverter

Para crear un convertidor de fecha y hora personalizado, subclase JsonConverter de esta manera:

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)

Paso 2:implementar la lectura()

Como desea personalizar la deserialización, deberá implementar Read(). No necesita implementar Write() (a menos que también vaya a usar el convertidor personalizado para la serialización).

Por ejemplo, puede usar DateTime.ParseExact() si solo desea poder analizar su formato exacto:

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() también funcionaría en la fecha y hora (2021-05-26 18:30:41.720) utilizada en este artículo:

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

Tenga cuidado al usar DateTime.Parse() ya que puede analizar una amplia gama de formatos. Si solo desea aceptar un formato muy específico, use ParseExact() en su lugar.

Paso 3:pase el convertidor personalizado a JsonSerializer

Para usar el convertidor personalizado, agréguelo a JsonSerializerOptions.Converters y luego pase las opciones a JsonSerializer.Deserialize(), así:

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)

Cuando JsonSerializer se encuentre con la propiedad HappenedAt, llamará al convertidor personalizado, que analizará correctamente el valor de fecha y hora.