Reputation: 4094
Just realised that my understanding about ASP.NET Core 6 Web API versioning is wrong.
This is my controller:
[ApiVersion("1.0")]
[ApiController]
[Authorize]
public class FundController
{
[MapToApiVersion("1.0")]
[Route("/Fund/v{version:apiVersion}/delta")]
public async Task<List<PortfolioHolding<Holding>>> Delta([FromQuery] Request dataModel)
{
}
}
What I want is to support route /Fund/v1.0/delta
and /Fund/delta
, when versioning not provided by the consumer (e.g. calling /Fund/delta
), the default version will be hit.
So I configured the versioning like this. However, when I call /Fund/delta
, I get a http 404 error.
But /Fund/v1.0/delta
will hit the correct controller.
What am I doing wrong?
services.AddApiVersioning(option =>
{
option.DefaultApiVersion = new ApiVersion(1, 0);
option.AssumeDefaultVersionWhenUnspecified = true;
option.ReportApiVersions = true;
});
Upvotes: 2
Views: 3810
Reputation: 13
Usually, it's pretty easy to do this that way. The disadvantage of this approach is that you need to manually change the "default" version of API with this attribute
[ApiController]
[Route("api/v1/[controller]")]
[Route("api/[controller]")]
[ApiVersion("1.0")]
Upvotes: 0
Reputation: 3960
Another way to do this without having [Route("api/[controller")]
on every controller is to implement and use IControllerConvention from Asp.Versioning.Conventions
internal class DefaultRouteHandler : IControllerConvention
{
public bool Apply(IControllerConventionBuilder builder, ControllerModel controller)
{
var attributeModel = new AttributeRouteModel();
var selectorModel = new SelectorModel();
attributeModel.Template = "api/[controller]";
selectorModel.AttributeRouteModel = attributeModel;
controller.Selectors.Add(selectorModel);
return true;
}
}
Then in your main...
services.AddApiVersioning(option =>
{
option.DefaultApiVersion = new ApiVersion(1, 0);
option.AssumeDefaultVersionWhenUnspecified = true;
option.ReportApiVersions = true;
})
.AddMvc(option => option.Conventions.Add(new DefaultRouteHandler()));
To prevent Swagger from showing duplicate (versioned + default) routes, you can do something like
builder.Services.AddSwaggerGen(x =>
{
x.DocInclusionPredicate((v, d) => d.RelativePath.Contains($"/{v}/", StringComparison.OrdinalIgnoreCase));
});
Upvotes: 0
Reputation: 61
The problem is that you have not specified the routes in the controller.
You should add the default route as well as the formatted version route. Then you should ensure that your endpoints have the version specified in the MapToApiVersion attribute.
Here is a code sample of what your controller should look like:
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("[controller]")]
[Route("[controller]/v{version:apiVersion}")]
public class FundController : ControllerBase
{
[MapToApiVersion("1.0")]
[Route("delta")]
[HttpGet]
public async Task<List<PortfolioHolding<Holding>>> DeltaV1([FromQuery] Request dataModel)
{
}
[MapToApiVersion("2.0")]
[Route("delta")]
[HttpGet]
public async Task<List<PortfolioHolding<Holding>>> DeltaV2([FromQuery]
Request dataModel)
{
}
}
Upvotes: 1