CarterCommunity / Carter

Carter is framework that is a thin layer of extension methods and functionality over ASP.NET Core allowing code to be more explicit and most importantly more enjoyable.
MIT License
2.05k stars 172 forks source link

Unable to bind a model with LocalDate property #275

Closed Deilan closed 3 years ago

Deilan commented 3 years ago

If a model has a property LocalDate (Noda Time), Bind<T> silently creates a new instance of T with all properties initialized with their default values.

Reproduced with DefaultJsonModelBinder, but not NewtonsoftJsonModelBinder

jchannon commented 3 years ago

What is the JSON you are POSTing

On Tue, 2 Mar 2021 at 10:09, Mikhail Ovchinnikov notifications@github.com wrote:

Post("/actors/_bulk", async (ctx) => { var collection = await req.Bind<Actor[]>(); // do something await res.AsJson(collection); });

Throws System.MissingMethodException:

No parameterless constructor defined for type 'Actor'

Using List instead won't help either:

var collection = await req.Bind<List>();

results in an empty list.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/CarterCommunity/Carter/issues/275, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAZVJSLVWVL3CTLAZNNVLDTBS2MBANCNFSM4YOT2AMA .

ritasker commented 3 years ago

Did using the NewtonsoftJsonModelBinder resolve your issue? You mention using Noda Time types, you may need to create a custom model binder using NodaTime.Serialization.SystemTextJson this will register all the type converters required for serialising the Noda Time types.

For example: https://gist.github.com/ritasker/fc5cfbfb82bcf28534d3ac1c3bd46ea7

Deilan commented 3 years ago

@ritasker Thank you very much for your help! You are right.

For some reason even just switching to Carter's NewtonsoftJsonResponseNegotiator and NewtonsoftJsonModelBinder was enough:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCarter(configurator: configurator =>
    {
        configurator.WithResponseNegotiator<NewtonsoftJsonResponseNegotiator>();
        configurator.WithModelBinder<NewtonsoftJsonModelBinder>();
    });
}
JoeStead commented 3 years ago

Glad using a different JSON deserialiser helped

jnysteen commented 1 year ago

Did using the NewtonsoftJsonModelBinder resolve your issue? You mention using Noda Time types, you may need to create a custom model binder using NodaTime.Serialization.SystemTextJson this will register all the type converters required for serialising the Noda Time types.

For example: https://gist.github.com/ritasker/fc5cfbfb82bcf28534d3ac1c3bd46ea7

I just hit this issue today and tried fixing it by using this gist, but I am unable to find both the WithModelBinder extension method and the ModelBinderBase class.

Next, I tried using the solution suggested in https://github.com/CarterCommunity/Carter/issues/275#issuecomment-789805687, but I again am missing the WithModelBinder extension method and now also the NewtonsoftJsonModelBinder.

I guess that these things existed in past versions of Carter - any idea on how to fix it in the current version?

jchannon commented 1 year ago

This might help. It might not.

https://stackoverflow.com/questions/69850917/how-to-configure-newtonsoftjson-with-minimalapi-in-net-6-0

On Sat, 24 Sep 2022 at 20:32, Jesper Nysteen @.***> wrote:

Did using the NewtonsoftJsonModelBinder resolve your issue? You mention using Noda Time types, you may need to create a custom model binder using NodaTime.Serialization.SystemTextJson https://www.nuget.org/packages/NodaTime.Serialization.SystemTextJson this will register all the type converters required for serialising the Noda Time types.

For example: https://gist.github.com/ritasker/fc5cfbfb82bcf28534d3ac1c3bd46ea7

I just hit this issue today and tried fixing it by using this gist, but I am unable to find both the WithModelBinder extension method and the ModelBinderBase class.

Next, I tried using the solution suggested in #275 (comment) https://github.com/CarterCommunity/Carter/issues/275#issuecomment-789805687, but I again am missing the WithModelBinder extension method and now the NewtonsoftJsonModelBinder.

I guess that these things existed in past versions of Carter - any idea on how to fix it in the current version?

— Reply to this email directly, view it on GitHub https://github.com/CarterCommunity/Carter/issues/275#issuecomment-1257051212, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAZVJRALUZQZBA5L37TPKDV75JMTANCNFSM4YOT2AMA . You are receiving this because you commented.Message ID: @.***>

jnysteen commented 1 year ago

This might help. It might not. https://stackoverflow.com/questions/69850917/how-to-configure-newtonsoftjson-with-minimalapi-in-net-6-0

Thanks, that link led me down the right path. The JsonOptions used when deserialising request contents can now be configured to work for NodaTime types like this:

...
using Microsoft.AspNetCore.Http.Json;
using NodaTime.Serialization.SystemTextJson;
...

services.AddCarter();
services.Configure<JsonOptions>(opt => opt.SerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb));

This blog post deserves a link and a quote:

Minimal APIs rely on a number of extension methods for serializing to/from JSON. They allow for JsonSerializerOptions to be provided but otherwise falls back to retrieving JsonOptions from HttContext.Request.Services. You can configure these options at startup:

builder.Services.Configure<JsonOptions>(opt =>
{
    opt.SerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy());
});

Note that you need to configure Microsoft.AspNetCore.Http.Json.JsonOptions not the class under the Mvc namespace.