ASP .NET Core + Entity Framework - Zmiana atrybutu modelu nie wpływa na prace aplikacji

Odpowiedz Nowy wątek
2019-12-02 11:26
0

Witam.
Zauważyłem pewien problem z modelem w aplikacji. Mam model menadżera, który posiada datę rozpoczęcia i zakończenia umowy. Z czego zakończenie umowy jest Nullable i w bazie również jest zaznaczone Allow null, a mimo to nie da się wykonać inserta.

        [Required]
        public DateTime AgreementStartDate { get; set; }
        public DateTime? AgreementEndDate { get; set; }

Błąd:
"The JSON value could not be converted to System.Nullable1[System.DateTime]. Path: $.agreementEndDate | LineNumber: 0 | BytePositionInLine: 222."

Bardzo uciążliwe, ponieważ ten błąd pojawia się dopiero po publikacji aplikacji. W trybie debug pod VS wszystko działa.

Pozostało 580 znaków

2019-12-02 12:39
0

Jeżeli dobrze pamiętam to dodany w Dotnet 3.0 serializer JSONa nie radził sobie zbyt dobrze z nullem w jakimś polu (miałem problemy jak przesyłałem wartość nullable w API i przychodziło coś w stylu "field": null). Może masz różne wersje frameworka w trakcie debuga i po publikacji? I np. debug ma jakiś poprawiony release.


Wszystkie miejsca, w których mnie znajdziesz w internecie: https://codewin.pl
Ekologiczne podejście do aplikacji? Dołącz do mojej przyszłorocznej inicjatywy: https://ekoapps.pl

Pozostało 580 znaków

2019-12-02 13:19
0

Jak szybko pochwaliłem, tak szybko się popsuło, nawet w VS w trybie debug. Te same błędy. Problem w tym, że podglądając request przeglądarką moje agreementEndDate nie jest NULL tylko jest pustym stringiem:

agreementStartDate: "2019-12-09T00:00:00.000Z"
agreementEndDate: ""

Mam jeszcze kilka innych klas i jedna z nich ma int? DeviceId, które też sypie tym samym błędem. Nie rozumiem co się dzieje... Dopisałem jeszcze w Startup.cs dla testu:

services.AddControllersWithViews()
    .AddJsonOptions(options => options.JsonSerializerOptions.IgnoreNullValues = true);

Niestety, to też nic nie daje...

Pozostało 580 znaków

2019-12-02 13:53
1

Potwierdzam, System.Text.Json.Json.JsonSerializer nie traktuje pustego stringa jako null, więc nie daje rady tego zdeserializować.

Ciężko mi to powiedzieć, czy to błąd, bo w zasadzie niezbyt wiem, czy faktycznie "" powinno być traktowane jako null, ale na zdrowy rozsądek to nie.

W każdym razie możesz sobie zbudować konwerter, na wzór tego:

private class Test
{
    [JsonConverter(typeof(NullableInt32ConverterFromEmptyString))]
    public int? test { get; set; }
}

private class NullableInt32ConverterFromEmptyString : JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.String)
        {
            string stringValue = reader.GetString();
            if (string.IsNullOrEmpty(stringValue))
                return null;

            if (int.TryParse(stringValue, out int value))
            {
                return value;
            }
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            return reader.GetInt32();
        }
        else if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        throw new JsonException();
    }

    public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options)
    {
        if (value.HasValue)
            writer.WriteNumberValue(value.Value);
        else
            writer.WriteNullValue();
    }
}

private static void Main(string[] args)
{
    var json = "{ \"test\": \"\" }";

    var data = JsonSerializer.Deserialize<Test>(json);
}

Alternatywnie możesz przerzucić się na Newtonsoft.Json zamiast System.Text.Json, bo on nie ma tego problemu.

edytowany 1x, ostatnio: Ktos, 2019-12-02 13:58

Pozostało 580 znaków

2019-12-02 15:21
0

GH wrzucony
The JSON value could not be converted - Model with nullable DateTime #434

@Ktos
Wykorzystałem twój konwerter do innego modelu, w którym właśnie int? się sypał. Niestety ale teraz dostaje

System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.

Zmieniłem MaxDepth na 64 to pokazuje ten sam błąd ale na końcu jest 64... Co w tym wszystkim najciekawsze? Dane dodają się do bazy, DeviceId jest w bazie NULL, ale teraz przeglądarka rzuca błędem

error:
   type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
   title: "One or more validation errors occurred."
   status: 400
   traceId: "|2d8246de-48882ab75c7cf487."
   errors:
      id: Array(1)
      0: "The value 'undefined' is not valid."
      length: 1

Pozostało 580 znaków

2019-12-02 19:01
1

System.Text.Json.JsonException: A possible object cycle (...)

To się pojawia przy serializacji czy deserializacji? Jak przy de- to pokaż tego JSONa. Względnie też może chodzić o model, patrz https://github.com/dotnet/corefx/issues/41002.

Może spróbuj wrócić do Newtonsoft.Json? ;)

edytowany 1x, ostatnio: Ktos, 2019-12-02 19:02

Pozostało 580 znaków

2019-12-03 00:05
0

System.Text.Json jest o wiele bardziej restrykcyjny i nie jest "userfriendly" jak Newtonsoft i to są te przypadki typu "" gdzie można się naciąć przy przejściu z Newtona na Texta.

A jeżeli chodzi o { get; set; } vs field, to:

Deserialization behavior

By default, property name matching is case-sensitive. You can specify case-insensitivity.
If the JSON contains a value for a read-only property, the value is ignored and no exception is thrown.
Deserialization to reference types without a parameterless constructor isn't supported.
Deserialization to immutable objects or read-only properties isn't supported. For more information, see GitHub issue 38569 on immutable object support and issue 38163 on read-only property support in the dotnet/corefx repository on GitHub.
By default, enums are supported as numbers. You can serialize enum names as strings.
Fields aren't supported.
By default, comments or trailing commas in the JSON throw exceptions. You can allow comments and trailing commas.
The default maximum depth is 64.

https://docs.microsoft.com/en[...]ation/system-text-json-how-to

edytowany 6x, ostatnio: WeiXiao, 2019-12-03 01:38

Pozostało 580 znaków

2019-12-03 09:24
0

@Ktos:
Jak wrócić do Newtonsoft.Json jeśli to wszystko dzieje się automatycznie przez System.Text?

Stacktrace do błędu z cyklicznością:

System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)
   at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

InnerException

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Agreements_Devices_DeviceId". The conflict occurred in database "TRON_JakarSystem", table "dbo.Devices", column 'ID'.
The statement has been terminated.
edytowany 2x, ostatnio: AdamWox, 2019-12-03 09:29

Pozostało 580 znaków

2019-12-03 09:51
1
services.AddMvc()
    .AddNewtonsoftJson();

W ConfigureServices().

Patrz https://docs.microsoft.com/en[...]visual-studio#jsonnet-support

Pozostało 580 znaków

2019-12-03 10:02
1

Dzięki bardzo za pomoc. Nie wiem dlaczego, ale od wczoraj czuje jakąś wewnętrzną satysfakcję w wytykaniu błędów w .NET Core firmie Microsoft :D

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0