Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default parameter value in MVC 4 Web API

I am curious why the ApiController handles default parameter values on actions differently than a 'regular' Controller.

This code works just fine, request to /Test means page gets value 1

public class TestController : Controller
{
    public ActionResult Index(int page = 1)
    {
        return View(page);
    }
}

This code doesn't work when a request is made to /api/Values. It fails with:

"The parameters dictionary contains a null entry for parameter 'page' of non-nullable type 'System.Int32' for method 'System.Collections.Generic.IEnumerable`1[System.String] Get(Int32)' in 'MvcApplication1.Controllers.Controllers.ValuesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."

public class ValuesController : ApiController
{
    public IEnumerable<string> Get(int page = 1)
    {
        return new string[] { page.ToString() };
    }      
}

Any hints on why this is?

like image 287
Joe Capka Avatar asked Apr 19 '12 17:04

Joe Capka


People also ask

What is FromBody and FromUri in Web API?

The [FromUri] attribute is prefixed to the parameter to specify that the value should be read from the URI of the request, and the [FromBody] attribute is used to specify that the value should be read from the body of the request.

What is difference between FromQuery and FromBody?

[FromQuery] - Gets values from the query string. [FromRoute] - Gets values from route data. [FromForm] - Gets values from posted form fields. [FromBody] - Gets values from the request body.

Which of the following is a valid default rule for parameter binding in Web API?

Default Parameter Binding in ASP.NET Web API By default, if the parameter type is of the primitive type such as int, bool, double, string, GUID, DateTime, decimal, or any other type that can be converted from the string type then Web API Framework sets the action method parameter value from the query string.

What is the default binding behavior of Web API?

By default, Web API extracts the value of the complex type from the request body, but here, we have applied the [FromUri] attribute. So now, Web API will extract the value of the Student properties from the query string instead of the request body.


1 Answers

Try adding the [FromUri] or [FromForm] parameter attribute.

public class ValuesController : ApiController
{
    public IEnumerable<string> Get([FromUri]int page = 1)
    {
        return new string[] { page.ToString() };
    }      
}

Mike Stall has two good posts about parameter binding in Webapi which does not work as it does in ASP MVC. The big problem to get used to is that you can only read the request body once in your pipeline. So if you need to read more than 1 complex object as a parameter, you probably need to resort to ModelBinding by parameter. I had a problem similar to yours when I was reading the content body earlier in the pipeline for logging purposes and did not realize about the read once restriction above and had to solve with my own custom model binder.

Explains model binding at http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx and then suggests a way to make WebAPI model binding more like ASP MVC http://blogs.msdn.com/b/jmstall/archive/2012/04/18/mvc-style-parameter-binding-for-webapi.aspx

like image 126
AlexGad Avatar answered Oct 11 '22 10:10

AlexGad