POST request from Postman fails model validation - c#

Inside my ASP.NET WebApi program, I have an Author model:
public class Author
{
public int Id { get; set; }
[Required] public string Name { get; set; }
}
I also have an AuthorsController, with a PostAuthor(Author author) method:
// POST: api/Authors
[ResponseType(typeof(Author))]
public async Task<IHttpActionResult> PostAuthor(Author author)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// etc.
}
When I send a POST request programmatically inside my unit tests, HTTP Status Code 201 Created is returned:
However, when I send a POST request using Postman, I receive HTTP Status Code 400 Bad Request instead:
As you can see, when I send a POST request using Postman, the argument passed into the PostAuthor(Author author) method is null, and model validation fails as a result:
What should I do to ensure that POST requests from Postman can be processed?

Couple of changes: define it as HttpPost and use FromBody like
// POST: api/Authors
[HttpPost]
[ResponseType(typeof(Author))]
public async Task<IHttpActionResult> PostAuthor([FromBody] Author author)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// etc.
}

Replace = with : in postman body, its a JSON after all.

If you send in application/json and your API wait as INBOUND JSON, so try to send in JSON format, something like
{
"Id":"6",
"Name":"P.G. Wodehouse"
}

Related

How to pass object to Web API as Parameter with HttpGet

I am working on .NET 6.0 Web API application. I need to pass object which is collection of string list to API with the purpose it will return data. I can do with HttpPost but since I am designing this API for the purpose of Get Record, what will be the right approach?
public class JobRoleDataView
{
public JobRoleDataView() { }
public List<string> Roles { get; set; }
}
this object will get more properties soon so it is not just List...
[HttpGet("SearchRecord")]
public async Task<IActionResult> SearchRecord(JobRoleDataView JobRoles)
{
//remaining code
return Ok(returnResponse);
}
error
TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
You can use [FromQuery] attribute and pass roles as querystring.
[HttpGet("SearchRecord")]
public async Task<IActionResult> SearchRecord([FromQuery]JobRoleDataView JobRoles)
{
//remaining code
return Ok(returnResponse);
}
}
The request url will be seen as below.
https://localhost:7009/WeatherForecast/SearchRecord?Roles=vishal&Roles=michel

Model binding not working in aspnet core web api

I am working on ASP.NET Core 2.1 Web API project. I am trying to follow this article: https://www.c-sharpcorner.com/article/jwt-json-web-token-authentication-in-asp-net-core/ but I am stuck at Action. My model class just won't bind to the input.
[AllowAnonymous]
[HttpPost]
public IActionResult Login([FromBody] LoginVM loginVM)
{
IActionResult response = Unauthorized(); // cant reach this point, my breakpoint is here
var user = AuthenticateUser(new UserModel { });
if (user != null)
{
var tokenString = GenerateJSONWebToken(user);
response = Ok(new { token = tokenString });
}
return response;
}
public class LoginVM
{
public string Username { get; set; }
public string Password { get; set; }
}
You're posting as x-www-form-urlencoded, but you have the [FromBody] attribute applied to the action param. These two things are fundamentally incompatible. To accept x-www-form-urlencoded (or multipart/form-data) you must apply the [FromForm] attribute to the param. If you have [FromBody], as you do now, then you can only accept something like application/json or application/xml (if you also enable the XML serializers).
If the issue is that you want to be able to accept both application/json and x-www-form-urlencoded request bodies, that is not possible. You'll need a separate action for each request body encoding, though you can factor out the actual meat of the action into a private method on the controller that both actions can utilize.
Choose "raw" in Body and "Content-Type" as "application/json" in postman and then try.

Model Binding HTTP Requests in ASP.Net Core WebAPI

I'm having an issue with an endpoint, it takes an object which isn't binding and consequently returning a 400 bad request.
I've gotten around this issue by passing in the individual properties of the object rather than the object itself, but would prefer the passing of an object.
WebClient webClient = new WebClient();
webClient.QueryString.Add("firstName", "value1");
webClient.QueryString.Add("lastName", "value2");
string result = webClient.DownloadString(url);
[HttpGet]
public async Task<IActionResult> DoSomething(string firstName, string lastName)
{
// this endpoint works perfectly
return Ok();
}
[HttpGet]
public async Task<IActionResult> DoSomething([FromBody]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
public class SubmitModel
{
public string FirstName {get; set;}
public string LastName {get; set;
}
By design, GET request does not contain data in the request body.
So when your Submit method recieves a request, it can't bind the model from the body as the data does not exist and therefore returns an bad request response.
As your method is named Submit, it sounds like you should use a POST request instead. POST request, by design, sends data in the request body and is suited for submitting data to the server.
Try it like this
[HttpPost]
public async Task<IActionResult> Submit([FromBody]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
I don't know if there is a good way to do what you're wanting. To get a little bit closer you can add this attribute to pull directly from the url
[HttpGet]
public ActionResult Get([FromUri]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
Another thing you can do if need be is create an extension method that reflects over the model and adds all the properties/values to the query string. Some good examples here How do I serialize an object into query-string format?

How to fix - The requested resource does not support http method 'POST'

Below is WebAPI action. On googling about the below error:-
The requested resource does not support http method 'POST'
I got number of links & updated my api accordingly but still I am getting the same error.
Web api not supporting POST method
ASP.NET Web Api: The requested resource does not support http method 'GET'
[AcceptVerbs("POST")]
[HttpPost]
[Route("rename/{userId}/{type}/{title}/")]
public IHttpActionResult Rename([FromBody] int userId, [FromBody] string type, [FromBody] string title)
{
//my api stuff
}
But still when calling the above via post man throws the error.
How do I get rid of this error??
Also is it possible to fix this without using [FromBody] attribute in the method parameters list?
Any help/suggestion highly appreciated.
Thanks.
You have declared route which requires url parameters
[Route("rename/{userId}/{type}/{title}/")]
So when you send request to api/customer/rename it does not match this method. You should remove parameters which you are passing in request body from route parameters
[Route("rename")]
Make sure that you have appropriate RoutePrefix("api/customer") attribute on your controller.
Second problem is multiple [FromBody] parameters. You will get can't bind multiple parameters error. There is limitation - you can mark only one parameter as FromBody. See Sending Simple Types notes:
Web API reads the request body at most once, so only one parameter of
an action can come from the request body. If you need to get multiple
values from the request body, define a complex type.
You should create complex type which will hold all parameters
public class RenameModel
{
public int UserId { get; set; }
public string Type { get; set; }
public string Title { get; set; }
}
And change method signature to
[HttpPost]
[Route("rename")]
public IHttpActionResult Rename(RenameModel model)
And send request data as application/x-www-form-urlencoded
[Route("rename/{userId}/{type}/{title}/")]
public IHttpActionResult Rename([FromBody] int userId, [FromBody] string type, [FromBody] string title)
The last answer is correct, you're asking for these parameters in the route, but saying that you expect them in the post body. Also, usually the route would begin with a noun rather than a verb. What is it you're renaming? (i.e. [Route("users/rename/{userId}/{type}/{title}")]
Based on your initial post, try this instead:
[HttpPost]
[Route("rename/{userId}/{type}/{title}" Name = "RenameUser"]
public IHttpActionResult Rename(int userId, string type, string title)
{
_myServiceMethod.Rename(userId, type, title);
return new StatusCodeResult(HttpStatusCode.Created, this);
}
Or, if you wanted to do a post with the info in the body:
Declare your data contract:
public class User
{
public string Type { get; set; }
public string Title { get; set; }
}
Then on the endpoint:
[HttpPost]
[Route("rename/{userId}", Name = "RenameUserPost")]
public IHttpActionResult RenameUserPost(int userId, [FromBody] User userData)
{
return new StatusCodeResult(HttpStatusCode.Created, this);
}
Note that in both returns 'this' refers to your controller class that inherits from ApiController. Verified both of these in swagger, and they accept POSTs and return status codes.
Hope this helps.
I had this error for wrong string in Route string on top of my action.
[Route("api/TestReaderPercentStudyHomework/AddOrUpdate")]

fiddler post + webapi 2 issue

This is my webapi 2 endpoint - the MVC duplicate suggestion is not relevant
[Route("Test2")]
[HttpPost]
public IHttpActionResult Test2([FromBody] Guid? guid)
{
return Ok();
}
when I use fiddler to manually test this using:
Content-Type: application/json
in the header and this payload in the body:
{"guid":"1c3c8edc-d87a-46dc-adbf-e7112bf16d22"}
The method is hit but the guid is null. Any ideas?
It can't be deserialized directly to Guid. Now, you are sending object from fiddler, something like:
public class SampleObject
{
public Guid guid {get; set;}
}
Try send just:
"1c3c8edc-d87a-46dc-adbf-e7112bf16d22"
in the body of the request.
You send response through header. Thats why you get null. You have to send request through body.
public class Test
{
public Guid guid {get; set;}
}
you have to sent request through body like
"1c3c8edc-d87a-46dc-adbf-e7112bf16d22"
and if you want to send request through header then your code will be like this
[Route("Test2")]
[HttpPost]
public IHttpActionResult Test2()
{
IEnumerable<string> headerValues=request.Headers.GetValues("MyCustomID");
var guid = headerValues.FirstOrDefault();
return Ok();
}

Categories

Resources