I have successfully set up API Versioning in my Core 2.1 API project.
http://localhost:8088/api/Camps/ATL2016/speakers?api-version=x.x
Versions 1.1
and 2.0
work but 1.0
fails with an ambiguity on the Get(string, bool)
Actions.
ASP.NET Core Web Server:
MyCodeCamp> fail: Microsoft.AspNetCore.Mvc.Routing.DefaultApiVersionRoutePolicy[1]
MyCodeCamp> Request matched multiple actions resulting in ambiguity. Matching actions:
MyCodeCamp.Controllers.Speakers2Controller.Get(string, bool) (MyCodeCamp)
MyCodeCamp> MyCodeCamp.Controllers.SpeakersController.Get(string, bool) (MyCodeCamp)
MyCodeCamp> fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
MyCodeCamp> An unhandled exception has occurred while executing the request.
MyCodeCamp> Microsoft.AspNetCore.Mvc.Internal.AmbiguousActionException: Multiple actions
matched. The following actions matched route data and had all constraints satisfied:
Controller Speakers2
is decorated with [ApiVersion("2.0")]
so it’s Get(string, bool)
action is version 2.0 so why can’t Versioning
tell them apart?
Microsoft.AspNetCore.Mvc.Versioning 3.0.0
(can’t install higher due to version conflicts)
Startup.cs:
services.AddApiVersioning(cfg =>
{ cfg.DefaultApiVersion = new ApiVersion(1, 1);
cfg.AssumeDefaultVersionWhenUnspecified = true;
cfg.ReportApiVersions = true; });
Controllers:
[Route("api/camps/{moniker}/speakers")]
[ValidateModel]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
public class SpeakersController : BaseController
{
. . .
[HttpGet]
[MapToApiVersion("1.0")]
public IActionResult Get(string moniker, bool includeTalks = false)
[HttpGet]
[MapToApiVersion("1.1")]
public virtual IActionResult GetWithCount(string moniker, bool includeTalks = false)
[Route("api/camps/{moniker}/speakers")]
[ApiVersion("2.0")]
public class Speakers2Controller : SpeakersController
{
...
public override IActionResult GetWithCount(string moniker, bool includeTalks = false)
Apparently versioning gets confused with the multiple Getxxx
IActionResult
s.
I got it to work by making the Get
action in the Speakers
controller
virtual
and then overriding
it in the Speakers2
controller
as a placeholder that will not be called. I also had to apply the [ApiVersion("2.0")]
only to the GetWithCount
action
and not the controller
.
[Authorize]
[Route("api/camps/{moniker}/speakers")]
[ValidateModel]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
public class SpeakersController : BaseController
[HttpGet]
[MapToApiVersion("1.0")]
[AllowAnonymous]
public virtual IActionResult Get(string moniker, bool includeTalks = false)
[Route("api/camps/{moniker}/speakers")]
public class Speakers2Controller : SpeakersController
public override IActionResult Get(string moniker, bool includeTalks = false)
{ return NotFound(); }
[ApiVersion("2.0")]
public override IActionResult GetWithCount(string moniker, bool includeTalks = false)