(Auto)Binding: The Struggle Is Real
For additional details and sample code read my article at CodeProject.com:
GitHub – raddevus/BindApi: Sample code for article for using auto-bind in dotnet webapi and JavaScript Fetch[^]
If you use JavaScript Fetch API to make requests to a .NET Core WebAPI and expect Model Binding and Parameter Binding to just-work, you may run into some problems as I have. Yesterday, I was trying to get a call to the simplest WebAPI method to work and it kept failing.
Here’s the method I was trying to hit using JS Fetch:
public ActionResult RegisterUser(string uuid)
[FromBody], [FromQuery], [FromForm]
, etc.)FromQuery
FromQuery WebAPI Defined This Way
I defined the WebAPI method in the following way:
[HttpPost] publicActionResultRegisterUser([FromQuery] string uuid)
JavaScript Fetch Call For FromQuery
fetch(`${baseUrl}User/RegisterUser?uuid=${currentUuid}`,{
method:'POST',
})
.then(response => response.json())
.then(data => console.log(data));
uuid
(exact same name as the WebAPI parameter) to the queryString.FromForm WebAPI Method
[HttpPost] publicActionResultRegisterUser([FromForm] string uuid)
JavaScript Fetch Call For FromForm
// 1. Create the FormData object
var fd = new FormData();
// 2. Append the name/value pair(s) for values you want to send
fd.append("uuid", currentUuid);
fetch(`${baseUrl}User/RegisterUser`,{
method:'POST',
body:fd, // add the FormData object to the body data which will be posted
})
.then(response => response.json())
.then(data => console.log(data));
FromBody WebAPI Method
I decided to see what would happen if I change the method Parameter to [FromBody] but not make the change to the JavaScript from the previous example (FromForm).
415 Error
When I did that and posted I got a 415 error (unsupported media type).
I gave up on that idea and then defined the WebAPI method with FromBody also.
FromBody WebAPI Method: The Big Issue
I know defined the WebAPI method like the following:
public ActionResult RegisterUser([FromBody] string uuid)
Spoiler Alert: Here’s The Explanation
uuid
as a string
value. That’s because, as we will discover, the WebAPI method is expecting to parse an object that contains a member named uuid
.JavaScript Fetch Call For FromBody
Second Try
I then tried the following set up for the data that I wanted to send:
varpostdata= {"uuid":currentUuid};
fetch(`${baseUrl}User/RegisterUser`,{
method:'POST',
body:JSON.stringify(postdata),
headers: {
"Content-Type":"application/json",
},
})
.then(response => response.json())
.then(data => console.log(data));
Notice that I have now added the header object to the fetch object. The header object allows us to send the Content-Type
header to let the receiving application know that we are posting JSON.
500 Error
When I posted, I received a 500 error but that was because I was attempting to use the value on the server side even though it hadn’t been supplied.
Nothing Works With WebAPI FromBody & String Parameter
The point is that the .NET Core auto-binding never works with any string you post to the method.
That’s because the auto-binding is expecting an object which contians a string named uuid.
You’d have to re-define the WebAPI method like the following:
[HttpPost] public ActionResult RegisterUser2([FromBody] Id uuid)
public class Id{
public string uuid{get;set;}
}
fetch(`/User/RegisterUser2`,{
method: 'POST',
body:
"{\"uuid\":\"test-this-value-10987\"}",
headers: {
'Content-type':'application/json; charset=UTF-8',
},
})
.then(response => response.json())
.then(data => console.log(data));
WebAPI Demands An Object
The WebAPI knows that a JSON object is coming in the body. You can’t get away from that, because the body is defined between the two { } curly brackets and that defines an object.
You can also create your postdata object (create an actual JavaScript object that contains the expected name (uuid) / value and then call stringify to post like the following:
var postdata = {uuid:"my-id-value-12345"};
fetch(`/User/RegisterUser2`,{
method: 'POST',
body:
JSON.stringify(postdata),
headers: {
'Content-type':'application/json; charset=UTF-8',
},
})
.then(response => response.json())
.then(data => console.log(data));
FromHeader WebAPI Method: This One Seems Odd, But Works
Define the method like the following:
public ActionResult RegisterUser( [FromHeader] string uuid)
FromHeader JavaScript Fetch API
fetch(`/User/RegisterUser`,{
method: 'POST',
headers:{ "content-type":"UTF-8",
"uuid":"1234-4578-838298"},
})
.then(response => response.json())
.then(data => console.log(data));
It works. It’s a lot easier than the FromBody one. But I’m not sure why we’d pass the value in the headers like this. It seems a bit odd. But, it means you can auto-bind values in the headers to your WebAPI methods and that is interesting.
There are a couple of other methods which are new to .NET Core 8.x (FromServices, FromKeyedServices) so I will not cover them for now.
Hope this helps someone who is stuck on that crazy [FromBody]
one. It is quite tricky.