4

I have a simple ASP.Net Web API 2 controller:

public class TestController : ApiController
{
    [Route("api/method/{msg?}")]
    [AcceptVerbs("GET", "POST")]
    public string Method(string msg = "John")
    {
        return "hello " + msg;
    }
}

And a simple HTML form to test it.

<form action="/api/method/" method="post">
    <input type="text" name="msg" value="Tim" />
    <input type="submit" />
</form>

When I load the page and submit the form the resulting string is "hello John". If I change the form's method from post to get the result changes to "hello Tim". Why hasn't the msg parameter been routed to the action when posted to the controller?

========== EDIT 1 ==========

Just-in-case the HTTP GET is distracting, this version of the controller also fails to receive the correct msg parameter from the posted form:

[Route("api/method/{msg?}")]
[HttpPost]
public string Method(string msg = "John")
{
    return "hello " + msg;
}

========== EDIT 2 ==========

I have not changed the default routing and so it still looks like this:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
6
  • Out of interest, why are you using the same method for both GET and POST requests? Typically GET would be used for retrieving a resource and UPDATE / POST would be used for modifying it. In that context it makes very little sense for the method to accept both verbs - If I had to hedge a bet, your issue would be a non issue if you separated this out too two methods. Commented Jan 21, 2015 at 14:28
  • The real app will probably just use POST, but GET are easier to just paste as URLs in the browser. So unless there's a good reason to differentiate I don't bother. Commented Jan 21, 2015 at 14:32
  • Depends if you consider the violation of REST principles a good reason not too... I would! Commented Jan 21, 2015 at 14:34
  • Indeed, though that's not what I'm asking. I've edited the question to include an POST only controller for you. Commented Jan 21, 2015 at 14:37
  • Have you changed the default routing config? If so, please post it as well. Commented Jan 21, 2015 at 14:51

1 Answer 1

4

Parameters in POST methods won't be deserialized out of the box if you are using an html form. Use the [FromBody] attribute to get the value of msg.

[HttpPost]
[Route("api/method")]
public string Method([FromBody] string msg)
{
    return "hello " + msg;
}

Otherwise you must use Fiddler (or a similar web debugger) to make a call to the POST method and pass the msg as a querystring.

If you really like to use an HTML Form without using [FromBody] attribute, try the following

[HttpPost]
[Route("api/method")]
public string Method()
{
    var msg = Request.Content.ReadAsFormDataAsync();
    var res= msg.Result["msg"];
    return "hello " + res ;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Interestingly [FromBody] does not seem to work with optional parameters. E.g. if I change the code to public string Method([FromBody] string msg = "John") then the call fails with an InvalidOperationException with the message "Optional parameter 'msg' is not supported by 'FormatterParameterBinding'"
I've found that a workaround for [FromBody] with an optional simple type parameter is to not make it optional and to structure your request body differently depending on whether you have values for your optional parameters: =stringvalue then msg will be "stringvalue" in WebAPI. msg= then msg will be null in WebAPI. You would have to define your default value of "John" inside your controller method but this would eliminate the InvalidOperationException. Don't forget to set your Content-Type header to application/x-www-form-urlencoded

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.