Description
Symptoms
The default route parameter name of OData entity key values is key; however, a service author may specify an alternate parameter name.
Consider the following OData service:
[ApiVersion( "1.0" )]
[ControllerName( "Candidates" )]
[ODataRoutePrefix( "Candidates" )]
public class CandidatesController : ODataController
{
public IHttpActionResult Get() =>
Ok( new[] { new Candidate() { Id = 1, Name = "John Doe" } } );
[ODataRoute( "({key})" )]
public IHttpActionResult Get( int key ) =>
Ok( new Candidate() { Id = key, Name = "Jane Doe" } );
[ODataRoute( "({key})/Resumes" )]
public IHttpActionResult GetResumes( int key ) =>
Ok( new[] { new Resume() { Id = 42, Name = "Resume ABC" } } );
}
This controller will route with or without API versioning applied. If the service is changed to use a key value parameter name of id instead of key, the route continues to work using standard, unversioned OData routes, but not with routes that use OData API versioning.
[ApiVersion( "1.0" )]
[ControllerName( "Candidates" )]
[ODataRoutePrefix( "Candidates" )]
public class CandidatesController : ODataController
{
public IHttpActionResult Get() =>
Ok( new[] { new Candidate() { Id = 1, Name = "John Doe" } } );
[ODataRoute( "({id})" )]
public IHttpActionResult Get( int id ) =>
Ok( new Candidate() { Id = id, Name = "Jane Doe" } );
[ODataRoute( "({id})/Resumes" )]
public IHttpActionResult GetResumes( int id ) =>
Ok( new[] { new Resume() { Id = 42, Name = "Resume ABC" } } );
}
Cause
Parameters bound to route values are updated in the ODataPathRouteConstraint during URI resolution. The extended VersionedODataPathRouteConstraint does not call the base implementation, which prevents custom route parameter key tokens from being remapped. The net result is that actions on OData services with key value segments other than key no longer route properly.