Search code examples
asp.net-mvcasp.net-web-api2asp.net-mvc-routing

Adding new parameter to a web API action method without disturbing the existing contract


I have an action method already written in my web api 2.0 project. I would like to add a new parameter without disturbing the existing contract. What is the best way to do that? Appreciate any best practice hints on this :)

Here's the code sample of what I intend to do:

Existing code:

[Route("{myId}",Name="MyId")]
Public IHttpActionResult Get(String myId)
{
  //Some more code here
}

Url: http://localhost:8888/webapi/1111

Expecting to do something like the below:

//I want to keep the route name same for backwards compatibility.
[Route("{myId}/{myName}",Name="MyId")]
Public IHttpActionResult Get(String myId,string? myName)
{
  //Some more code here
}

Url: http://localhost:8888/webapi/1111/John The Url mentioned above hits the method rightly, but I never get the second parameter (myName) populated with John.

Thanks everyone for any help towards this. Sree.


Solution

  • In your example you have myName as string? which is not allowed as:

    The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'

    A test controller was created to implement you action

    [RoutePrefix("webapi")]
    public class TestsController : ApiController {
        [HttpGet]
        [Route("{myId}/{myName}", Name = "MyId")]
        public IHttpActionResult Get(string myId, string myName) {
            //Some code to show the values of the parameters
            return Ok(new { myId = myId, myName = myName });
        }
    }
    

    When tested with webapi/1111/John the following response is returned

    {"myId":"1111","myName":"John"}
    

    which does include the value for MyName as John

    If backwards uri webapi/1111 is tried, a NotFound response is returned as the template does not match the new action.

    To fix this you need to make the myName parameter optional. To learn more about that check

    Optional URI Parameters and Default Values

    The new route will look like

    //NOTICE THE `?` ON THE {myName} TEMPLATE
    [Route("{myId}/{myName?}", Name = "MyId")]
    public IHttpActionResult Get(string myId, string myName = null) {...}
    

    You will notice that myName was made optional in the route {myId}/{myName?} and in the action parameter (string myId, string myName = null)

    Now when tested with webapi/1111 the following response is returned

    {"myId":"1111","myName":null}
    

    Which would match your expected result for backwards compatibility.