简体   繁体   中英

ASP.Net Core 3.1: Controller method always recieves NULL parameter from HttpPost call

I've created a brand new Visual Studio 2019 web app using ASP.Net Core 3.1 with an MVC pattern.

My controller has an HttpPost method that should have an incoming Json object (I use [FromBody] for the incoming parameter).

No matter what I try, the incoming parameter is always Null. I've tried changing the parameter to a string, and modifying the Model to be a simple 3 field class, but it still comes in as a null.

I used Chrome's Developer Tools to make sure that my page is sending the Json object correctly from a JavaScript Post callback (and also used Postman to do the same) with the same result: my parameter is still Null.

What do I need to do to get the parameter to come in as an actual value?

My controller:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

using canvasApiLib.API;
using CanvasGrades.Models.AuxiliaryModels;

namespace CanvasGrades.Controllers
{
    public class FinalGradeController : Controller
    {

        public async Task<IActionResult> Index()
        {
            // Course Name
            dynamic courseDetails = await clsCoursesApi.getCourseDetails(accessToken, apiUrl, canvasCourseId);
            ViewData["CourseName"] = courseDetails.name;

            // Course Term
            dynamic courseTerm = await clsEnrollmentTermsApi.getEnrollmentTerm(accessToken, apiUrl, canvasAccountID, termNum);
            ViewData["CourseTerm"] = courseTerm.name;

            return View();
        }

        [HttpPost]
        public async Task<IActionResult> LoadTable([FromBody]DTParameters dtParameters)
        {
            //DTParameters dtParameters = new DTParameters();

            if (dtParameters == null)
            {
                dtParameters = new DTParameters();
            }
        }
    }
}

My DTParameters model:

public class DTParameters
{
    public int Draw { get; set; }
    public DTColumn[] Columns { get; set; }
    public DTOrder[] Order { get; set; }
    public int Start { get; set; }
    public int Length { get; set; }
    public DTSearch Search { get; set; }
    public IEnumerable<string> AdditionalValues { get; set; }
}

Most examples that I saw stated to tweak the app.UseMVC instantiation in the Configure call of the Startup.cs file, but mine doesn't have one:

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

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

(ADDED)

{"draw":1,"columns":[{"data":"studentName","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":"studentEMail","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":"finalGrade","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":"lastAttendDate","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":"bannerID","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":"crn","name":"","searchable":true,"orderable":true,"search":{"value":"","regex":false}}],"order":[{"column":0,"dir":"asc"}],"start":0,"length":10,"search":{"value":"","regex":false}}

I retried my simple parameter again, noticing that original ID field that I sent was an integer, but when I made it a string (like the Model stated) it came in with no issue.

public class SimpleParam
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Foo { get; set; }
}

{"id": "1", "name": "fred", "foo": "bob"}

So, that means I'm going to have to figure out what's wrong with my DTParameters model.

The error is "dir": "asc". You need to either change this to an int ("dir": 0), or decorate the class property or the enumeration with

[JsonConverter(typeof(JsonStringEnumConverter))]

or put this in startup.cs

public void ConfigureServices(IServiceCollection services)
{

    services
        .AddControllers()
        .AddJsonOptions(options => 
           options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())
        );

    //...
 }

Your input beautified:

{
    "draw": 1,
    "columns": [
        {
            "data": "studentName",
            "name": "",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        }
    ],
    "order": [
        {
            "column": 0,
            "dir": "asc"
        }
    ],
    "start": 0,
    "length": 10,
    "search": {
        "value": "",
        "regex": false
    }
}

Your Datatables classes with correct decoration (See above DTOrderDir):

public class DTParameters
{
    public int Draw { get; set; }
    public DTColumn[] Columns { get; set; }
    public DTOrder[] Order { get; set; }
    public int Start { get; set; }
    public int Length { get; set; }
    public DTSearch Search { get; set; }
    public IEnumerable<string> AdditionalValues { get; set; }
}

public class DTColumn
{
    public string Data { get; set; }
    public string Name { get; set; }
    public bool Searchable { get; set; }
    public bool Orderable { get; set; }
    public DTSearch Search { get; set; }
}

public class DTOrder
{
    public int Column { get; set; }
    public DTOrderDir Dir { get; set; }
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum DTOrderDir
{
    ASC,
    DESC
}

public class DTSearch
{
    public string Value { get; set; }
    public bool Regex { get; set; }
}

Read here for more info: JavaScriptSerializer - JSON serialization of enum as string

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM