简体   繁体   中英

“400/The input was not valid” when calling ASP.NET Core Web API

I'm testing my Web API using postman and am getting back a "400 Bad Request" or "The input was not valid" in Postman. The break point on the first line of my action isn't getting hit. How can I figure out what's going on behind the scenes?

I would show a screenshot of Postman, but I can't get the image to upload. It's simply a POST with several fields specified for the Body. Here's the URL:

http://localhost:52126/api/v1/itinerary

Here's the action:

[HttpPost]
[Route("api/v1/itinerary")]
public async Task<ActionResult> AddItineraryAsync([FromBody] Itinerary itinerary)
{
    if (!ModelState.IsValid) // Break point on this line not getting hit!
    {
        return BadRequest(ModelState);
    }

    await Logic.AddItineraryAsync(itinerary);

    return Ok();
}

Originally, I didn't have [FromBody] specified for the action. It doesn't work either way. What can I check to figure out what's going on?

Clarification (in response to Chris Pratt):

I'm in the early stages of writing my first mobile app, and, being a bottom-up kind of guy, I'm getting some Web API calls working first. I assume I'll be passing JSON from the mobile app to this server layer.

I haven't done anything having to do with anti-forgery tokens in this Web API project, so I assume those aren't in play...unless that's something that's coming from Postman.

Removing the parameter from the action does allow the execution to fall through to my break point, so the error does seem to be with ASP.NET's attempt at binding.

After digging around in Postman a bit, I did see that the header was specifying x-www-form-urlencoded for the Content-Type. I changed it to application/json , as you suggested. However, that didn't seem to make a difference.

More Info:

After trying what Carl suggested below, I have more information. Execution dropped down into the action and I got a look at what is being passed from Postman. Here it is:

----------------------------179455694862693501539465
Content-Disposition: form-data; name="StartPoint"

Tacoma
----------------------------179455694862693501539465
Content-Disposition: form-data; name="EndPoint"

Portland
----------------------------179455694862693501539465
Content-Disposition: form-data; name="TravelDate"

2018-8-21 07:00:00 AM
----------------------------179455694862693501539465
Content-Disposition: form-data; name="Name"

Test Itinerary
----------------------------179455694862693501539465
Content-Disposition: form-data; name="UserAccountId"

2
----------------------------179455694862693501539465
Content-Disposition: form-data; name="Comment"

Just doin' some testing.
----------------------------179455694862693501539465--

The Json deserialization is failing with:

JsonReaderException: Input string &#x27;----------------------------179455694862693501539465&#x27; is not a valid number.

What are these numbers and where are they coming from?

ModelState is only validated if it's able to successfully deserialize the post body/bind.

You were not specific in your question, but it sounds as if you're posting as x-www-form-urlencoded . If that's the case, you should not have [FromBody] . However, bear in mind that it's an either/or situation, so if you want to eventually post via JSON, then you should keep the attribute and post JSON from Postman instead.

Aside from that, ensure that you're either not using antiforgery token validation or that you are posting a valid token along with the request. Failing antiforgery validation will short circuit the request and return a 400 immediately.

If you are posting JSON, ensure that your JSON is valid. If the JSON is invalid, you'll get a 400 immediately.

I was trying it like your [FromBody] Itinerary itinerary but got a work around. The 2.1 framework has Issues https://github.com/aspnet/Mvc/issues/7609 and https://github.com/aspnet/Mvc/issues/7799 . I got this working in 2.1: client javascript is unchanged:

var payload = JSON.stringify({ "name": document.getElementById('firstname').value, "email": document.getElementById('email').value, "captcha": grecaptcha.getResponse() });
var oReq = new XMLHttpRequest();
oReq.ContentType = "application/json";

oReq.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {

        document.getElementById("update").innerHTML = this.responseText;
    }
    else document.getElementById("update").innerHTML = "not 4&200! : " + this.responseText;
};

oReq.open('POST', 'api/u');
oReq.send(payload);

and the controller has:

[Route("api/[controller]")]
//  [ApiController] // works either way
public class UController : ControllerBase
{
    [HttpPost]
    public async Task<string> signUp()
    {
        String body;
        using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
        {
            body = await reader.ReadToEndAsync();
        }

        UserSignup user = JsonConvert.DeserializeObject<UserSignup>(body);

        return user.email;
    }
}

Soon to be on https://github.com/Hover-Us/

Solution From Comment:

For 179455694862693501539465, it seems you are using PostMan with application/x-www-form-urlencoded as Content-Type.
I suggest you follow steps:
1. keep your api with AddItineraryAsync([FromBody] Itinerary itinerary);
2.clear your headers in postman
3. Body tab choose raw with JSON(application/json)
4. enter valid json string or just with {}
5. make sure there is no additional headers except application/json as Content-Type in headers tab.
6. send request to check whether api method will be hit.

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