Calling web api PUT FromBody "value" always null - asp.net-web-api

I am trying to call the ValuesController WebApi controller (that gets created by default) "PUT" method using cURL. No matter what I do, send value="abc", "abc" or "=abc" as I saw suggested in other questions for the POST method, to no avail.
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
I also tried changing the Content-Type to application/json and application/x-www-form-urlencoded, nothing seems to work.
curl -H -d "=TEST" -X PUT http://localhost:30960/api/values/5
Is this a bug in ASP.NET 5 Web Api or is there a different format I need to use when calling?

In order to make it work you need to pass it as a simple string:
"any value here"
There is even a test for this behaviour
Remember to add an application/json Content-Type header when issuing a request.
I've just tested it for both PUT and POST requests.
Using curl it's:
curl -H "Content-Type: application/json" -d "'Test'" -X PUT http://localhost:[port]/api/values/5

If you are posting data as application/x-www-form-urlencoded then you need to remove the FromBody attribute. This is a change in behavior from MVC5/WebAPI2.
If you are posting data as application/json, then you need the FromBody and also a bindable typ. Example:
public class Person
{
public string Name {get; set;}
}
for data { "Name" : "James"}

Related

How to set content type for #SpringBootTest

I have a SpringBootTest class which uses SpringRunner:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT)
public class DemoApplicationTests {
#Test
public void testCustomerList() {
get("http://localhost:8080/list")
.then()
.assertThat()
.statusCode(200)
.body("size()", is(2));
}
}
I'd like to change the accept header for the test, much like I'd do with curl:
curl --header "Accept: application/json" curl http://localhost:8080
I've tried with:
get("http://localhost:8080/list").contentType(MediaType.APPLICATION_JSON)
However I get the error "ContentType cannot be applied to Response options".
Can you recommend a way to fix it?
Thanks!
You can add accept header using accept method:
.accept(MediaType.APPLICATION_JSON_VALUE)
See also accept vs content type
Accept header is used by HTTP clients to tell the server what content types they'll accept. The server will then send back a response, which will include a Content-Type header telling the client what the content type of the returned content actually is
Seems I've figured it out.
As get is io.restassured.RestAssured.get (my apologies for not specifying it),
then it should be:
given()
.contentType("application/json").
.get("http://localhost:8080/list")
You need to specify the accept header.
get("http://localhost:8080/list")
.accept(MediaType.APPLICATION_JSON_VALUE)
.then()
.assertThat()
.statusCode(200)
.body("size()", is(2));

.NET Core ApiController-Attribute infers wrong binding

I currently have a problem with the new .NET Core 2.1 attribute [ApiController] and I don't know how to solve it. If I apply the attribute I have problems with inference. Without everything works fine.
I have a controller with the [ApiController] attribute and an action that should accept a couple of different headers and a viewmodel.
The action looks like this:
[HttpPut]
public async Task<IActionResult> MyAction(MyHeaderClass myHeaders, [FromBody]MyViewModel myViewModel)
{
var resultObject = await DoSomething();
return Json("");
}
The MyHeadersClass looks like this:
public class MyHeadersClass
{
[FromHeader(Name = "X-Some-Id")]
[Required]
public string SomeId { get; set; }
[FromHeader(Name = "X-SomeGuid-Id")]
[Required]
public Guid? SomeGuid { get; set; }
}
If I try to start my application it fails because .NET Core 2.1 tries to infer that MyHeaderClass is bound by request body.
The only thing that works is to apply the [FromHeader] attribute to my MyHeaderClass but then I have to specify a single header with
{
X-Some-Id: string,
X-SomeGuid-Id: string
}
But I want to have a single header for every property and that worked without the attribute. What could I change to get it working with the [ApiController] attribute?
Not sure why you want to send your header info in the request body when you are marking your header with attribute [FromHeader]
The only thing that works is to apply the [FromHeader] attribute to my
MyHeaderClass but then I have to specify a single header with
{
X-Some-Id: string,
X-SomeGuid-Id: string
}
I tested your code on .NET core 2.1 using POSTMAN it works fine with and without [FromBody] Arttribute with [ApiController] present.
Here is the Raw HTTP request from POSTMan with Header values in Header section and not in the Request Body:
POST /api/My/Register HTTP/1.1
Host: localhost:5001
Content-Type: application/json
X-Some-Id: idstring
X-SomeGuid-Id: guidstring
Postman-Token: 7fc48dc9-cb0b-46fd-8419-7ad4e3676855
{
"username":"rajesh",
"password":"password"
}
The point is you need to add header values in correct place in HTTP request as mentioned in HTTP request from POSTMAN Tool in below screenshot:

Can Spring REST convert path variables to an object, like it is done with request parameters with #RequestBody?

With Spring REST the request parameters are converted to an object in case you do a post, and you use #RequestBody, for example:
#RestController
#RequestMapping("/reservations")
class ReservationController{
...
#RequestMapping(value="/postByName")
public Reservation save(#RequestBody Reservation reservation) {
return reservationRepository.save(reservation);
}
...
}
Then I do, and this works fine, a Reservation is created:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"name\" : \"Foo\" }" http://localhost:8080/reservations/postByName
My question is if something exists when you use path variables instead of request parameters. So I should do something like:
curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/reservations/postByName/Foo
Now I do it by hand: in the code I create a Reservation with new and put the path variables in it.
The documentation says:
A #PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. You can also register support for parsing additional data types. See the section called “Method Parameters And Type Conversion” and the section called “Customizing WebDataBinder initialization”.

QueryString truncated in WebAPI RequestBody when request is manually composed?

I've confirmed I have the dropdown set to post and the URL is correct, because the string gets passed into my Web API project without error. However it is cutting everything off of the string after the first parameter
Request Headers:
User-Agent: Fiddler
Host: localhost:52888
Content-Length: 35
Content-Type: application/x-www-form-urlencoded
Request Body:
=name=TestName&date=10/15/2014
In the Web API project the only part that is passed is name=Test Name
I'm confident the query string is in the right format. I'm wondering if anyone else can point me in the direction of what I might be missing.
If I remove the = in front of the request body then nothing is received
A signature like AddCourse([FromBody] string courseRequest) tells WebAPI to look for a POST parameter named courseRequest. But (when it is properly formatted) your request body doesn't have that parameter - instead it has name and date. When you misformat the request body by prepending an = character, it apparently causes the parser to decide that name=test is the value. But the second part of the query string is after an &, and is clearly a different parameter. It has nowhere to bind that parameter, so it just gets dropped.
There are at least two solutions here. One would be to pass the parameters on the query string instead of in the request body, and use a method signature like: AddCourse(string name, string date) (note removed of [FromBody]).
Another would be to create a model object that encapsulates the request, something like
public class AddCourseModel{
public string Name {get;set;}
public string Date {get;set;}
}
and use that as the argument to your method: AddCourse([FromBody] AddCourseModel model).

Test json post request with curl

When testing my spring code with the following curl request, it fails with a http 400 bad request (The request sent by the client was syntactically incorrect.)
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"ids":[1,2]}' <someurl>
My corresponding Spring controller has a method that looks like this
#RequestMapping(value = "someurl", method = RequestMethod.POST)
public #ResponseBody List<Result> multiple(#RequestBody List<Integer> ids){
List<Result> list = new ArrayList<>();
for(int id : ids){
// do something with id and add to result list
}
return list;
}
My url is correct, I'm almost sure my curl request is also correct, so I don't know what's wrong with my code, this is my first POST request, the GET's are all working.
EDIT:
I'm using a linux terminal
#RequestBody expects just a JSON array if used to annotate a List. You'll have to do one of two things:
Create a type to represent your POST data, with a single private List<Integer> ids field. Change your controller method signature to use that type instead of List<Integer>.
Change your JSON POST to:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '[1,2]' <someurl>
Either solution should work.

Resources