简体   繁体   中英

ASP.NET Core - weird behavior with [FromBody]

I have an ASP.NET Core web app that works fine, when using this controller implementation:

[HttpPost]
public ActionResult SetAssignment()
{
    string b = "";

    using (StreamReader rdr = new StreamReader(Request.Body)) b = rdr.ReadToEnd();
    Assignment asg = JsonConvert.DeserializeObject<Assignment>(b);

    // asg is valid here

    // ... do other stuff ...
}

But it does NOT work when using this implementation:

[HttpPost]
public ActionResult SetAssignment([FromBody] Assignment asg)
{
    // asg is always NULL here

    // ... do other stuff...
}

Theoretically, these implementations should be identical (although the second would be way more elegant), no?

I seem to be missing something...

The way this method is called looks like this, btw:

function asgupdate() {
   var asp = {};
   asp.AssignmentId = $("#asp_idx").val();
   ...
        
   $.ajax({
      type: "POST",
      url: "/Project/SetAssignment",
      data: JSON.stringify(asp),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: function (r) {
          ...
      }
   });
};

The JSON request does get sent by the browser and it look correct (afaict).

The assignment model looks like this:

  public class Assignment
    {
        [Key]
        public int AssignmentId { get; set; }
        [Required]
        public int CrewMemberId { get; set; }
        [Required]
        public int ProjectId { get; set; }
        [DisplayName("Function")]
        public string Function { get; set; } = "";
        public string? Account { get; set; }
        public float Rate { get; set; } = 0;
        public float PrepWeeks { get; set; } = 0;
        public float ShootWeeks { get; set; } = 0;
        public float WrapWeeks { get; set; } = 0;
        public float PostWeeks { get; set; } = 0;
        public DateTime Created { get; set; } = DateTime.UtcNow;
        public DateTime Updated { get; set; } = DateTime.UtcNow;
        public AssignmentTypes? AssignmentType { get; set; } = AdditionalClasses.AssignmentTypes.SALARYNORMAL;
        public virtual CrewMember CrewMember { get; set; }
        public virtual Project? Project { get; set; }
     }

Ok, the solution was a mix of several things, thanks to @dbc for pointing me in the right direction...

  1. I wrongly assumed that the automatic JSON conversion would be identical to Newtonsoft.JSON, which it is definitely NOT.

  2. Since System.Text.Json is more strict in how it interprets stuff, I had to add some options:

builder.Services.AddControllers().AddJsonOptions(x =>
    {
        x.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
        x.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
    });
  1. Since Enums are also treated differently (the NumberHandling options does NOT apply to Enum parsing, I had to change the generating JavaScript to always send an integer instead of a string. I tried to use JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()), however that broke the sending back of the enum (because it would now send the string name of the enum instead of the integer value back to the webfrontend, which couldn't deal with it).

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