Closed
Description
Hi all,
I'm having trouble setting up versioning by URL segment. After figuring out how to add the version to the route template, I'm faced with these situations:
- The routing works as expected. Each call is directed to the correct version of the api;
- Swagger does not recognize the template, and instead of registering routes like this
api/v1/values
it is showing like thisapi/v{version:apiVersion}/values
which, as expected, causes a lot of troubles; - And finally, when trying to show the document for another version, I get and exception saying my routes are not unique.
Here is how I've setup the application:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
});
services.AddOData().EnableApiVersioning();
services.AddODataApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddSwaggerGen(a =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
var info = new Info
{
Title = "My API Title",
Version = description.ApiVersion.ToString(),
Description = "My API Description"
};
if (description.IsDeprecated)
info.Description += " NOTE: This API has been deprecated";
a.SwaggerDoc(description.GroupName, info);
}
a.ParameterFilter<SwaggerDefaultValues>();
var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, $"{PlatformServices.Default.Application.ApplicationName}.xml");
a.IncludeXmlComments(filePath);
a.DescribeAllEnumsAsStrings();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, VersionedODataModelBuilder versionedModelBuilder, IApiVersionDescriptionProvider versionDescriptionProvider)
{
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Expand().Filter().OrderBy().Count();
routeBuilder.MapVersionedODataRoutes("odata", "api/v{v:apiVersion}", versionedModelBuilder.GetEdmModels());
});
app.UseSwagger();
app.UseSwaggerUI(a =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in versionDescriptionProvider.ApiVersionDescriptions)
{
a.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName);
}
});
}
SwaggerDefaultValues.cs
public class SwaggerDefaultValues : IParameterFilter
{
public void Apply(IParameter parameter, ParameterFilterContext context)
{
if (!(parameter is NonBodyParameter nonBodyParameter))
return;
if (nonBodyParameter.Description == null)
{
nonBodyParameter.Description = context.ApiParameterDescription.ModelMetadata?.Description;
}
if (context.ApiParameterDescription.RouteInfo == null)
return;
if (nonBodyParameter.Default == null)
{
nonBodyParameter.Default = context.ApiParameterDescription.RouteInfo.DefaultValue;
}
parameter.Required |= !context.ApiParameterDescription.RouteInfo.IsOptional;
}
}
So, am I doing something wrong? Is this scenario supported?
Thanks in advance.