How to retrieve HttpPost parameters in c# - c#

So I know that this works:
[HttpPost]
public string functionthatiuse()
{
string id = "";//does nothing
return relevantinfo;
}
Then I use this Chrome POST extension shown below and I have a break point in the function which is how I know it reaches it. It's literally an empty post request basically.
But when I try to post with parameters I'm having trouble. Ideally I want to do something like this:
[HttpPost]
public string functionthatiuse(string idx)
{
string id = ""; //does nothing and is different from idx
return relevantData;
}
but when I try to use it I get an error back. I'm pretty sure it's because I'm not formatting the content body correctly and I've tried putting other stuff in the content body, but nothing has really worked. Does anyone know how I can send POST parameters to this function using this extension? The format of what I'm doing in code should be basically the same (part of a requirement).
Edit:
Here's a picture of the error:

According to microsoft here: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
You have to add "[FromBody]" in the parameter list. You can only have one of these types of parameters.
Also in the chrome post extension under headers you need to enter:
Name: Content-Type
Value: application/json

Related

How can I create a method to get a string of an element and assert its changes

I'm quite new to unit testing and c#.
I have an area on a page with a url: https://www.testurl.com (example)
I have a couple of tick boxes that can change the displayed url on the page.
Example of tick boxes: Http, .net, testurl2
There boxes will change the value of the url and i need to check if the url does change when those boxes are ticked.
How can i create a method for the url so i can call it every time a box is ticked and use an assert for the expected value?
I have created a Method for the test url as follows:
void TestUrl()
{
string url = driver.FindElement(By.CssSelector("div[class='ui action input'] input[type='text']")).Text;
}
And i tried to assert it this way (lets say, after clicking the http:// tick box, changing https:// to http://):
string httpUrl = "http://testurl.com";
Assert.AreEqual(httpUrl, TestUrl());
I get the following issue: Argument 2> cannot convert from void to object.
I understand the issue, but i cannot think on a way to get to use the method TestUrl() as i want to.
Hopefully the question is clear, Using examples as i cannot use the urls i am working on as they are confidential.
You just need to change
void TestUrl()
{
string url = driver.FindElement(By.CssSelector("div[class='ui action input'] input[type='text']")).Text;
}
to be
string TestUrl()
{
return driver.FindElement(By.CssSelector("div[class='ui action input'] input[type='text']")).Text;
}
Now your method will return string so you can compare it

Binding single value from the body of a POST with MVC

I am implementing a protocol in ASP.NET MVC, and I need to be able to bind data from a request made like this:
curl -H "Content-Type: application/json" -d 'true' http://example.com/operation/some_id
I have tried using the [FromBody] attribute on the parameter in my controller, like this:
public ActionResult Operation(string id, [FromBody] bool setSomething)
The above code does not work, as it throws an exception when MVC attempts to set setSomething to null. If I change setSomething to a string, it always gets set to null, so I am unable to parse it to a bool in the action.
I don't have the luxury of changing 'true' to '=true' as I have read elsewhere when similar questions were asked. The POST generated from the curl command above is set in stone. What I need is some way of taking the value true (which is valid json, even without a key) from the body of the POST and assigning it to setSomething. I also need to do this in a way that doesn't prevent me from assigning some_id to id, as I already have working with a custom route.
Does anyone know how this can be accomplished in MVC or Web API?
Any help is appreciated.
I found a solution, but it's more of a workaround.
When the body of a POST is just true or false but nothing more, there is no key to bind this value to. Therefore, MVC doesn't really have anything it can do other than run the value through a JSON deserializer, which succeeds without setting any parameters in the action.
In the end, I had to read the value directly from Request, as described in MVC controller : get JSON object from HTTP body?.
I ended up using similar code:
public ActionResult Operation(string id)
{
var req = Request.InputStream;
req.Seek(0, SeekOrigin.Begin);
string rawBody = new StreamReader(req).ReadToEnd();
bool setSomething = false;
if(bool.TryParse(rawBody, out setSomething))
{
// Do something with 'setSomething'
return Json(new { id = id, status = setSomething });
}
throw new ArgumentException(string.Format("{0} is not a valid boolean value", rawBody));
}
As you can see, I removed setSomething from the parameter list entirely, and rely on reading the raw input stream of the request in order to get the value. This is in no way elegant, and does not make use of all the goodies we get from the MVC framework, but it works.

Submitted POST content overwrite additonal URL params

I submit data via a xhr request which contains POST data along with some URL params where the POST data is a JSON string.
Here is a sample controller and a sample url
public ActionResult Update(string collection)
{
/* method body */
}
somepath/SomeController/Update?_id=r43r34r34r&collection=astring
If the POST data now looks like
{
collection: 'SomeString'
}
MVC overwrite the param from the URL so that within the controller the collection string has 'SomeString' as value instead of 'astring'. Is there a way to prevent this behavior?
The only way around this, beyond using a custom model binder to prioritise the URI, would be to either:
Change the name of the parameter in the query string and in the action method parameters to something that isn't in the POST request body.
Pick up directly from the query string in the controller:
var aCollection = Request.QueryString["collection"].ToString();
If you change your method signature to Update(string[] collection) you might get (i'm not sure) all the values.

Why does ASP.NET Web Api model binding uses the parameter type to determine the source of the value?

Since a few days I'm trying to create my own web api controller. Duo to the rest conventions I need to use a post request to create an object. To get concrete, Im having this controller with this action:
public class ReservationController : ApiController
{
[HttpPost]
public void Create(int roomId, DateTime arrivalDate)
{
//do something with both parameters
}
}
This code is not working when I fire a post request at it, I'm receiving a 404 exception something like this:
No action was found on the controller 'Some' that matches the request.
The reason for it is that simple types are read from the query string, complex types from the body, according to this aricle. The web api uses the parameters to match the action to a request and can't therefore map my action to the request.
I do know that I can use the [frombody] tag, but you can only apply that to one parameter and I have 2. I also know that I can create a wrapper object which have both the parameters, but I'm not willing to use wrappers for all my calls.
So I do know that I can work around this by these methods. I also think that this is caused by the fact that the body of the post request can only be read once. But my actual question is:
Why is the source of a parameter determined by it's type and not by it's availability, especially when the conventions state that you should make for example a post request for creation? In MVC this is the case, why isn't it in the web api?
Best regards,
BHD
FINAL UPDATE
Since I'm getting some upvotes, problably more people are facing the same question. In the end it comes to this: Web-Api != MVC. It's simply not the same thing and the web api team made different design decisions than the mvc team I guess.
It seems that you have a fundamental misunderstanding of how Web API actually works.
Web API routing is driven off of verbiage, not the method names. "SomeMethod" actually translates to zero useful information for Web API. As a result, if I post
api/some/some?id=1
OR
api/some/somemethod?id=1
OR EVEN
api/some/?id=1
and the SomeMethod endpoint is the ONLY available POST, it will hit that endpoint.
As such, first of all, make sure you have only one POST on that api controller. If you do, POSTing to it from any test client using either of the query strings above will work just fine.
You can use the [FromBody] attribute on the parameter to force it to read from the body of the HTTP POST instead of the Uri. This is opposed to the [FromUri] attribute which does the opposite.
[HttpPost]
public void SomeAction([FromBody] int id)
{
//do something with id
}
Are you sure you're actually putting the id in the body? It could also be a routing issue. If this still doesn't work then maybe you should use Fiddler and copy the RAW output of your HTTP message here.
If you're packing multiple values into the body such as with JSON then you should use a model which should automatically be deserialized to:
public class PostModel
{
public int ID { get; set; }
public int SomeOtherID { get; set; }
}
[HttpPost]
public void SomeAction(PostModel postModel)
{
//do something with postModel.ID and postModel.SomeOtherID
}
You can actually do this straight out of the box in WebAPI, at least in 2.2 (.Net version 4.5.2). Your controller is correct. Using your controller, if you call it with a HTTP POST like this (tested through Fiddler):
http://localhost:58397/api/Reservation?roomId=123&arrivalDate=2015-12-17
You'll get the correct values of roomId = 123 and arrivalDate = 17.12.2015.
I suspect there's something wrong in your call to the WebAPI. Maybe post that call if you're still not getting it to work.

How do I pass an object in a WebAPI PUT?

I'm new to ASP.NET MVC and it's my first time working with an API.
I'm trying to do a PUT, given an object. However, after starting the application and looking at the available API, it shows my PUT URL as the following, without any option for arguments.
/api/File
Shouldn't it be something like /api/File/{}?
Controller
[HttpPut]
public void PutFile (FileData file)
{
...
}
If I'm doing this completely wrong, please let me know!
That URL is correct since the object you are sending should be passed in the body of the request with the correct content type.... probably multipart/form-data if you are uploading a file. If FileData is not a file and just a complex object then you could use application/x-www-form-urlencoded for forms or application/json for AJAX.
tforester answer is correct, but just to add. You need to use the FromBodyAttribute to tell webapi that the non primitive object (e.g. FileData) is expected and it's in the body of the incoming request. e.g.
[HttpPut]
public void PutFile ([FromBody]FileData file)
{
...
}

Categories

Resources