Search code examples
c#asp.net-coreasp.net-core-routing

ASP.NET5 MVC 6 routing with optional parameter / default parameter value


I'm building Restful style API in VS2015, C#, ASP.NET5 MVC6 stack and I having some trouble when it comes to routing.

I'm using attributes directly in controller:

[HttpGet("machine/{machineId}-{cnt:int}")]
public IActionResult GetReportsByMachineId(string machineId, int cnt)
{
    var item = _reportRepository.GetReportsByMachineId(machineId, 0, cnt);
    if ((item == null) || (!item.Any()) )
    {
        return HttpNotFound();
    }
    return new ObjectResult(item);
}

and it works when I call api/report/machine/[machineName]-5 - I receive 5 documents from the database.

But I would like to make cnt parameter optional with default value - so the call for api/report/machine/[machineName] would be valid.

Based on http://stephenwalther.com/archive/2015/02/07/asp-net-5-deep-dive-routing I've tried so far:

[HttpGet("machine/{machineId}-{cnt:int=10}")] - controller don't catch api/machine/{machineName} (I get welcome page code)

[HttpGet("machine/{machineId}-{cnt?}")] - app wont start (I don't even get MVC welcome page)

[HttpGet("machine/{machineId}-{cnt:int?}")] - app wont start (like above)

Any ideas?

Code for whole controller (I don't have any other routes specified): http://pastebin.pl/view/11050284


Solution

  • Optional URI Parameters and Default Values

    You can make a URI parameter optional by adding a question mark to the route parameter. If a route parameter is optional, you must define a default value for the method parameter.

    [HttpGet("machine/{machineId}/{cnt:int?}")]
    public IActionResult GetReportsByMachineId(string machineId, int cnt = 10) {...}
    

    In this example, api/report/machine/nazwa_maszyny/10 and api/report/machine/nazwa_maszyny return the same resource.

    Alternatively, you can specify a default value inside the route template, as follows:

    [HttpGet("machine/{machineId}/{cnt:int=10}")]
    public IActionResult GetReportsByMachineId(string machineId, int cnt) {...}
    

    This is almost the same as the previous example, but there is a slight difference of behavior when the default value is applied.

    • In the first example ("{cnt:int?}"), the default value of 10 is assigned directly to the method parameter, so the parameter will have this exact value.

    • In the second example ("{cnt:int=10}"), the default value of "10" goes through the model-binding process. The default model-binder will convert "10" to the numeric value 10. However, you could plug in a custom model binder, which might do something different.