I receive a null value always in web api rest post request to a controller
In my controller
[HttpPost]
public HttpResponseMessage PostCustomer([FromBody]Customer customer)
{
System.Diagnostics.Debug.WriteLine(customer); #CustomerApp.Models.Customer
System.Diagnostics.Debug.WriteLine(customer.FirstName); #null
}
Model
public class Customer
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Request:
POST: http://localhost:21894/api/customer/postcustomer
Content-Type: application/json
body: {FirstName: "xxxx", LastName: 'yyyy'}
I tried the following solutions but nothing works out
https://myadventuresincoding.wordpress.com/2012/06/19/c-supporting-textplain-in-an-mvc-4-rc-web-api-application/
How to get POST data in WebAPI?
Can anybody guide me with help or the correct link
Answer:
Made a curl request instead of dealing with postman as like this gave me the solution
$ curl -H "Content-Type: application/json" -X POST -d '{"FirstName":"Jefferson","LastName":"sampaul"}' http://localhost
:21894/api/customer/postcustomer
I think you mean to have a Customer object as input like below instead of string
public HttpResponseMessage PostCustomer([FromBody]Customer customer)
{
Well make this below change and try reposting the request. It should work
public HttpResponseMessage PostCustomer(Customer customer)
{
return OK(customer.FirstName);
}
Request:
POST: http://localhost:21894/api/customer/postcustomer
Content-Type: application/json; charset=utf-8
{"Id":101,"FirstName":"xxxx","LastName":'yyyy'}
set your entity to be a customer not a string
[HttpPost]
public Customer PostCustomer(Customer customer)
{
System.Diagnostics.Debug.WriteLine(customer);
return customer;
}
Make sure you have [HttpPost] attribute on your method also no need for the [FromBody]
Related
I am trying to write an API to handle webhook posts from Clover and their header specifies content-Type: application/json
for some reason my HttpPost method is rejecting the post with a 404 error (I assume it's my method) I can post to my endpoint no problem with Postman as long as my content-type is not application/json - as soon as I switch to that I get 404 as well
I'm missing something basic here :/ any ideas?
If I post (using Reqbin) my end point accepts and returns 200 OK
POST /auctionapi/Auction HTTP/1.1
Host: www.someweb.com
Content-Length: 60
{"verificationCode": "b860be7e-6ac4-4b56-8ac6-f44cf238a296"}
and if I change the content-type I get 404...
POST /auctionapi/Auction HTTP/1.1
Host: www.someweb.com
Content-Type: application/json
Content-Length: 60
{"verificationCode": "b860be7e-6ac4-4b56-8ac6-f44cf238a296"}
My code...
[Route("[controller]")]
[ApiController]
public class AuctionController : ControllerBase
{
private readonly PCSOAuctionsContext _context;
public AuctionController(PCSOAuctionsContext context)
{
_context = context;
}
[HttpPost("receive")]
public async Task<IActionResult> receive()
{
return StatusCode(200, "Thanks for using the API");
}
}
Try doing something like this and see if that resolve the 404. The HttpPost is being sent content type of json, but your method is not setup to receive it, therefore it will 404 because a proper route is not being found.
[Route("pcsoauctionapi/[controller]")]
[ApiController]
public class AuctionController : ControllerBase
{
private readonly PCSOAuctionsContext _context;
public AuctionController(PCSOAuctionsContext context)
{
_context = context;
}
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "PCSO Auction API", "Online" };
}
[HttpPost("receive")]
public async Task<IActionResult> receive([FromBody] object jsonData)
{
return StatusCode(200, "Thanks for using the API");
}
}
I just tested my above method and it works just fine. So something is wrong with your Clover request. Here is result from swagger.
It shouldn't make a difference but don't set the content length and try sending then. Also can you post the CURL request clover is making. That will definitely reveal where issue is. here is my curl request.
curl -X 'POST' \
'https://localhost:7777/api/V1/receive' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{"verificationCode": "b860be7e-6ac4-4b56-8ac6-f44cf238a296"}'
I enabled Swagger in my asp.net core 3.1 API by following the usual MS docs.
https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=visual-studio
It works fine.
The following controller works great in Postman.
myBody has its Body1 and Body2 fields bound from the POST request's json body.
myHeader has its Header1 and Header2 bound from the request's two "Header1" and "Header2" headers.
namespace MyApi.Controllers
{
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult Post(
[FromHeader] MyHeaders myHeaders,
MyBody myBody)
{
return Ok();
}
}
public class MyHeaders
{
[FromHeader]
public string Header1 { get; set; }
[FromHeader]
public string Header2 { get; set; }
}
public class MyBody
{
public string Body1 { get; set; }
public string Body2 { get; set; }
}
}
However Swagger UI only passes 1 json object for the two headers:
[swagger ui][1]
And it generates a corresponding curl command:
curl -X POST "https://localhost:5001/test" -H "accept: */*" -H "myHeaders: header1,string,header2,string" -H "Content-Type: application/json" -d "{\"body1\":\"string\",\"body2\":\"string\"}"
The problem is the -H "myHeaders: header1,string,header2,string" portion. Model binding sets myHeaders.Header1 and .Header2 to null, as expected, because the header is named "myHeaders".
Replacing the portion with **-H "Header1: cat" -H "Header2: dog" works correctly.
Asp.net is clever enough to map separate headers into a single action parameter by matching their names. But how can I get Swagger have multiple headers the UI, so its curl command works?
I know I could replace [FromHeader] MyHeaders myHeaders with [FromHeader] string Header1, [FromHeader] string Header2, but I want to avoid that. There will be dozens of actions that all receive the same set of headers.
Solution is given in Yura's answer in How to use [FromHeader] attribute with custom model binding in Asp.Net Core 2.2
It is to change [FromHeader] MyHeaders myHeaders to [FromQuery] MyHeaders myHeaders.
This gets Swagger UI working, even though the FromQuery seems to be contradicted by the FromHeader attribute on Header1 and Header2.
The fixed code is:
public class TestController : ControllerBase
{
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult Post(
[FromQuery] MyHeaders myHeaders, // FromHeader is changed to FromQuery
MyBody myBody)
{
return Ok();
}
}
public class MyHeaders // unchanged
{
[FromHeader]
public string Header1 { get; set; }
[FromHeader]
public string Header2 { get; set; }
}
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"
}
I'm testing an API with fiddler using the following header and body and POSTing at http://localhost:50063/api/image:
User-Agent: Fiddler
Content-Type: application/json; charset=utf-8
Host: localhost:50063
Content-Length: 32330
{"filename": "bot.png", "file": "base64 image ellided for brevity"}
Example code from tutorial
[ApiController]
[Produces("application/json")]
[Route("api/Image")]
public class ImageController : Controller
{
// POST: api/image
[HttpPost]
public void Post(byte[] file, string filename)
{
string filePath = Path.Combine(_env.ContentRootPath, "wwwroot/images/upload", filename);
if (System.IO.File.Exists(filePath)) return;
System.IO.File.WriteAllBytes(filePath, file);
}
//...
}
First I got error 500 with the filename being null. I added [ApiController] Attribute to the controller class and I get error 400 filename invalid.
When I make the same request here the filename binds to the complex class:
[HttpPost("Profile")]
public void SaveProfile(ProfileViewModel model)
{
string filePath = Path.Combine(_env.ContentRootPath, "wwwroot/images/upload", model.FileName);
if (System.IO.File.Exists(model.FileName)) return;
System.IO.File.WriteAllBytes(filePath, model.File);
}
public class ProfileViewModel
{
public byte[] File { get; set; }
public string FileName { get; set; }
}
Why is that happening?
Request content can only be read from the body once.
In first example, after populating array it can populate string as body has already been read.
In second example it populates the model in one read of the body.
Once the request stream is read for a parameter, it's generally not possible to read the request stream again for binding other parameters.
Reference Model Binding in ASP.NET Core
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();
}