0

I've tried all the solutions I've found, but most don't apply to my issue. I am sending post requests using JSON, and up to 3.0 they worked fine.
You can see in my controller I have [FromBody] and my model has properties. Those were the two issues I saw from other people pop up. You can also see my request values match the name of my model and there are none missing. I can't find anything else that might be causing this issue.

Edit - Based on the comment below I checked the Json rules in place. Initially the default rule was in place that made the first character of value names lower case. It does that on the way down, but I don't know how to tell if that is affecting it when sending values to the server. Is there a breakpoint I can put in somewhere to see the post values before they are sent to the controller?

Edit2 - Changing startup to this makes it so the model isn't null, but all the values are default. Strings are null, ints are 0.

services.AddControllers().AddJsonOptions(o =>
            {
                o.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
            });

It looks like most of the json options to do with name changing don't affect deserializing from what I can see.

Startup.cs

   public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();


            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            //services.AddMvc();

            services.AddTransient<AuthService>();
            services.AddTransient<LocationService>();
            services.AddTransient<MessageService>();
            services.AddTransient<AutoAssignService>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseAuthentication();

            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthorization();


            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    }

Request Model

public class CensusManagementSearch
{
    public int LocationId { get; set; }
    public int PracticeId { get; set; }
    public string Name { get; set; }
    public int StatusId { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public bool Print { get; set; }
}

My controller method

[HttpPost]
public IActionResult PostCensusManagement([FromBody] CensusManagementSearch search)
{
}

And here's the data I'm sending in my requestenter image description here

Jhorra
  • 6,233
  • 21
  • 69
  • 123
  • `the issue`: this information is not really helpful. It does not say what exactly did not work, i.e. did you get any error messages anywhere, did you try to debug the issue to make sure that it actually does the intended thing. – jazb Dec 11 '19 at 06:13
  • @Jazb If you think this information has no value I would say you don't understand the problem. If you search for post values are null for .net core web apis you will find dozens of questions on stack overflow about it. Most are because they are not wrapping values in a class, don't have [from body], or aren't sending a value that's not nullable. I'm showing that none of those can be the case by the code above. – Jhorra Dec 11 '19 at 06:27
  • In addition there is no error. Only the problem listed in my title. The post values are null on the controller. Even though in the debug screenshot you can see all the values are there. I posted the statup.cs in case I need some additional line of code due to the changes with upgrading to 3.0, though I haven't thus far found anything that would affect this issue. – Jhorra Dec 11 '19 at 06:28
  • 3
    Maybe it's tangentially related to [this change](https://stackoverflow.com/questions/55666826/where-did-imvcbuilder-addjsonoptions-go-in-net-core-3-0)? – ProgrammingLlama Dec 11 '19 at 06:44
  • 1
    @John_ReinstateMonica I'm leaning towards something like that. I'll check those out. If they work I'll let you know and you can put it as the answer. – Jhorra Dec 11 '19 at 06:51
  • @John_ReinstateMonica Do you know how I can check the post values before they are sent to the controller? Maybe in the middleware I can put a break point to see? – Jhorra Dec 11 '19 at 07:48
  • 1
    Yeah, that's probably how I'd do it. You'll probably need to read the body and then rewind it. [This might help](https://elanderson.net/2017/02/log-requests-and-responses-in-asp-net-core/) – ProgrammingLlama Dec 11 '19 at 07:50
  • 1
    If there's some kind of error with binding the payload to your model, you're able to see it on the `ModelState` property. Is `ModelState.IsValid` equal to `false`? – silkfire Dec 11 '19 at 09:00
  • @silkfire Based off your suggestion I went through and found the problem was the date format. I hadn't even considered that to be a problem as 12/10/2019 worked fine in .net core 2.2. I don't know why the date format matters with 3.0, but if you put this as the answer I'll mark it accepted. – Jhorra Dec 11 '19 at 17:12
  • Can you paste the actual json payload instead of the rendered version from the request info? Just to make sure there's nothing odd in there. – Lasse V. Karlsen Dec 11 '19 at 18:02

1 Answers1

2

Usually when a JSON payload fails to bind to the model of a controller action, you will see that ModelState.IsValid equals to false. Expanding the ModelState.Values property while debugging and drilling down will give you a detailed error about what failed during parsing of the JSON.

Remember that ASP.NET Core 3.0 uses a new, native JSON engine instead of JSON.NET, which is far more limited. This could be the reason why some properties/types aren't parsed properly now.

To use a custom date format, you have to implement your own converter:

public class DateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateTime.ParseExact(reader.GetString(), "MM/dd/yyyy", CultureInfo.InvariantCulture);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture));
    }
}


// In ConfigureServices() of Startup.cs

services.AddControllers()
        .AddJsonOptions(options =>
         {
             options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
         });
silkfire
  • 24,585
  • 15
  • 82
  • 105