Die Json.NET-Deserialisierung des DateTimeOffset-Werts schlägt für DateTimeOffset.MinValue ohne Zeitzone fehl

Die Json.NET-Deserialisierung des DateTimeOffset-Werts schlägt für DateTimeOffset.MinValue ohne Zeitzone fehl

Das Problem scheint nur reproduzierbar, wenn die Zeitzone der Maschine TimeZoneInfo.Local ist hat einen positiven Offset von UTC, z.B. (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna . Ich konnte es in Zeitzonen mit einem nicht positiven Offset wie UTC-05:00 nicht reproduzieren oder UTC selbst.

Genauer gesagt in JsonReader.ReadDateTimeOffsetString() DateTimeOffset.TryParse wird angerufen mit DateTimeStyles.RoundtripKind :

if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
{
    SetToken(JsonToken.Date, dt, false);
    return dt;
}

Dies verursacht anscheinend einen Unterlauffehler in Zeitzonen mit einem positiven UTC-Offset. Wenn ich im Debugger mit DateTimeStyles.AssumeUniversal parse stattdessen wird das Problem vermieden.

Möglicherweise möchten Sie Newtonsoft ein diesbezügliches Problem melden. Die Tatsache, dass die Deserialisierung eines bestimmten DateTimeOffset Zeichenfolge schlägt nur fehl, wenn die Zeitzone des Computers bestimmte Werte falsch zu sein scheint.

Die Problemumgehung ist IsoDateTimeConverter zu verwenden um Ihren DateTimeOffset zu deserialisieren Eigenschaften mit IsoDateTimeConverter.DateTimeStyles auf DateTimeStyles.AssumeUniversal setzen . Außerdem ist es notwendig, den automatischen DateTime zu deaktivieren Erkennung integriert in JsonReader durch Setzen von JsonReader.DateParseHandling = DateParseHandling.None , was vorher erfolgen muss der Leser beginnt, den Wert für Ihren DateTimeOffset zu parsen Eigenschaften.

Definieren Sie zuerst den folgenden JsonConverter :

public class FixedIsoDateTimeOffsetConverter : IsoDateTimeConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?);
    }

    public FixedIsoDateTimeOffsetConverter() : base() 
    {
        this.DateTimeStyles = DateTimeStyles.AssumeUniversal;
    }
}

Nun, wenn Sie den JsonSerializerSettings ändern können Verwenden Sie für Ihren Controller die folgenden Einstellungen:

var settings = new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None,
    Converters = { new FixedIsoDateTimeOffsetConverter() },
};

Wenn Sie den JsonSerializerSettings Ihres Controllers nicht einfach ändern können Sie müssen DateParseHandlingConverter greifen von dieser Antwort auf Wie man verhindert, dass eine einzelne Objekteigenschaft in eine DateTime konvertiert wird, wenn es sich um eine Zeichenfolge handelt und wenden Sie es sowie FixedIsoDateTimeOffsetConverter an zu Ihrem Modell wie folgt:

[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
public class RootObject
{
    [JsonProperty("revisedDate", NullValueHandling = NullValueHandling.Ignore)]
    [JsonConverter(typeof(FixedIsoDateTimeOffsetConverter))]
    public DateTimeOffset? RevisedDate { get; set; }
}

DateParseHandlingConverter muss auf das Modell selbst angewendet werden und nicht auf RevisedDate -Eigenschaft, da der JsonReader 0001-01-01T00:00:00 bereits erkannt haben als DateTime vor dem Aufruf von FixedIsoDateTimeOffsetConverter.ReadJson() gemacht.

Aktualisieren

In Kommentaren schreibt @RenéSchindhelm:Ich habe ein Problem erstellt, um Newtonsoft davon in Kenntnis zu setzen . Es ist Die Deserialisierung des DateTimeOffset-Werts schlägt abhängig von der Zeitzone #1731 des Systems fehl .


Dies ist, was ich verwende, um das Problem in .NET Core 3 zu beheben.

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
                options.SerializerSettings.DateParseHandling = DateParseHandling.None;
                options.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal });
            });
...

Ändern Sie DateTimeOffset bis DateTime Problem gelöst.