I encountered this interesting (frustrating) problem recently after upgrading from .NET Core 2.2 to 3.1. Previously I would POST data to the web app, with the receiving method looking something like this:
public IActionResult OnPostAddNewDataAsync([FromBody]MyClass data)
{
//...
}
where MyClass
might be something like this:
public class MyClass
{
public string Field1 {get; set;}
public integer Value1 {get; set;}
}
(For reference, to hit the endpoint from Javascript, you can do it like this:
await PostDataAsync("AddNewData", {
"Field1": "Hello I am",
"Value1": 7
});
async function PostDataAsync(handler, data)
{
return await $.ajax({
url: window.location.pathname + "?handler=" + handler,
type: "POST",
contentType: "application/json",
headers:
{
RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val()
},
data: JSON.stringify(data)
});
}
it took me a while to figure that out!).
This worked fine.
After updating .NET Core 3.1, many of my POST methods stopped working, and the [FromBody]
value would be null.
Note: As part of my upgrade to .NET Core 3.1 I removed references to Newtonsoft.Json
, deciding instead to try and use the new System.Text.Json
. This would turn out to be important!
[FromBody] attribute The ASP.NET Core runtime delegates the responsibility of reading the body to an input formatter. Input formatters are explained later in this article. When [FromBody] is applied to a complex type parameter, any binding source attributes applied to its properties are ignored.
The [FromBody] attribute can be applied on only one primitive parameter of an action method. It cannot be applied to multiple primitive parameters of the same action method.
The [FromBody] attribute which inherits ParameterBindingAttribute class is used to populate a parameter and its properties from the body of an HTTP request. The ASP.NET runtime delegates the responsibility of reading the body to an input formatter.
As mentioned, references to Newtonsoft.Json
were removed, leaving any automatic Json conversion to be dealt with by System.Text.Json
. It turns out that this was the cause of the problem as System.Text.Json
is not as flexible (Microsoft themselves say so, and that it is intended to be so: How to migrate from Newtonsoft.Json to System.Text.Json).
Before .NET Core 3, ASP.NET Core used Newtonsoft.Json
internally, and now it uses System.Text.Json
instead.
An example is with a numeric field, e.g MyClass.Value1
. If from Javascript you pass "10" or 10, Newtonsoft.Json
will cope with that and recognise both as 10. With System.Text.Json
by default that field cannot have surrounding quotes, and if in the Json you posted it did you'd be getting a null [FromBody]
value.
The quickest solution to this problem is to revert to Newtonsoft.Json
for these cases, and that is easily done by:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages().AddNewtonsoftJson();
//All your other code:
//...
}
This is taken directly from here.
Having made this change everything worked as expected again.
I am aware that System.Text.Json
can be configured with custom parsers to handle these kind of situations (which I do use elsewhere), but I have dozens of POST methods and rather than updating all of them to work with the new way, it was a lot easier to do as described above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With