Search code examples
asp.net-web-apiasp.net-web-api2asp.net-web-api-routing

ASP.Net Web API 2 attribute-routed HTTP POST action not getting correct parameter


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 }
        );
    }
}

Solution

  • 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 ;
    }