Hi, in of our .Net Core API's I implemented Microsoft ASP.NET API Versioning, but it seems it's not picked up by Swagger.
Code example for a v2 version:
cs
[ApiVersion("2")]
[Route("api/v{version:apiVersion}/{tenantid}/timeline")]
public class TimelineController : Controller
{
}
This results in

with this Swagger json that also contains strange data:
javascript
{
"swagger": "2.0",
"info": {
"version": "v2",
},
"basePath": "/",
"paths": {
"/api/v{version}/{tenantid}/timeline/default": {
"get": {
"tags": ["Timeline"],
"operationId": "ApiV{versionByTenantidTimelineDefaultGet",
"parameters": [{
"name": "version",
"in": "path",
"required": true,
"type": "string"
}],
}
}
}
}
The version is now treated as a parameter. Can I fix this by configuration? Or am I doing something wrong?
Additionally, having a controller with multiple HttpGet actions that map to different API versions causes an exception "NotSupportedException: Multiple operations with path 'v{version}/Values' and method 'GET'. Are you overloading action methods?". The class is defined as:
namespace Controllers
{
[ApiVersion("1.0", Deprecated = true)]
[ApiVersion("2.0")]
[Route("v{version:apiVersion}/[controller]")]
public class ValuesController : Controller
{
// GET: api/values
[HttpGet, MapToApiVersion("1.0")]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
[HttpGet, MapToApiVersion("2.0")]
public string GetV3() => "Hello world v2!";
}
}
@kloarubeek found a temporary way to fix the first problem:
services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate((version, apiDescription) =>
{
var values = apiDescription.RelativePath
.Split('/')
.Skip(1);
apiDescription.RelativePath = version + "/" + string.Join("/", values);
var versionParameter = apiDescription.ParameterDescriptions
.SingleOrDefault(p => p.Name == "version");
if (versionParameter != null)
apiDescription.ParameterDescriptions.Remove(versionParameter);
return true;
});
options.SwaggerDoc("v1", new Info
{
Version = "v1",
Title = $"API v1"
});
});
thanks, it works! I made a slight change to the version replacement because our routes start with /api and that wasn't supported in your code snippet 馃槈:
var values = apiDescription.RelativePath
.Split('/')
.Select(v => v.Replace("v{version}", version));
apiDescription.RelativePath = string.Join("/", values);
this turns _api/v{version}/{tenantid}/timeline_ into _api/v2/{tenantid}/timeline_
Can't seem to find the DocInclusionPredicate extension method in the 6.0.0-beta902 package. What am I missing?
@kloarubeek If you have multiples versions this code will not work. The method DocInclusionPredicate is called for every version and on the second call will get the RelativePath modified from the first call.
@AngelVHS I'm using the latest preview 6.0.0-preview-0055.
@fabiano thanks, I hope it's a temporary solution. @AngelVHS I replaced the package
"Swashbuckle":`` "6.0.0-beta902"
with these two:
"Swashbuckle.SwaggerGen.Master": "6.0.0-T2016120822",
"Swashbuckle.SwaggerUi": "6.0.0-beta902"
(keeping Swashbuckle results in errors)
Thank you @kloarubeek, can you please point me to the feed where that package can be found?
Ok, thank you both but I really have 2 versions so this workaround will not work for me :(
@AngelVHS My snippet is working with multiples versions. You only have to change it if your api start with "/api" (not my scenario).
@fabiano the thing is, with the preview packages I don't have the MultipleApiVersions option, so how can I define my 2 versions?
@AngelVHS Here:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate((version, apiDescription) =>
{
var values = apiDescription.RelativePath
.Split('/')
.Skip(1);
apiDescription.RelativePath = version + "/" + string.Join("/", values);
var versionParameter = apiDescription.ParameterDescriptions
.SingleOrDefault(p => p.Name == "version");
if (versionParameter != null)
apiDescription.ParameterDescriptions.Remove(versionParameter);
foreach (var parameter in apiDescription.ParameterDescriptions)
parameter.Name = char.ToLowerInvariant(parameter.Name[0]) + parameter.Name.Substring(1);
return true;
});
options.SwaggerDoc("v1", new Info
{
Version = "v1",
Title = "API v1"
});
options.SwaggerDoc("v2", new Info
{
Version = "v2",
Title = "API v2"
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseSwagger();
app.UseSwaggerUi(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1");
options.SwaggerEndpoint("/swagger/v2/swagger.json", "API v2");
});
}
I don't probably have the right SwaggerUi package as the UseSwaggerUi extension method I am using doesn't support the syntax shown. The one I am using has this signature "public static IApplicationBuilder UseSwaggerUi(this IApplicationBuilder app, string baseRoute = "swagger/ui", string swaggerUrl = "/swagger/v1/swagger.json")"
I'm using the latest version available on the preview feed: https://github.com/domaindrivendev/Ahoy#preview-builds
Thank you @fabiano but I am really back to my starting point getting the NotSupportedException as I have 2 GET methods in the same controller that in this way are being picked up by any version. I think the problem is that the implemented mechanism is disregarding the Route attribute parameter when selecting the methods to inspect rendering it impossible to distinguish between the 2 methods in the same way that the versioning API does.
Hello everybody, any suggestion on how to use api version in query string and not path?
Hello, i write an operation filter to achieve my requirements:
public class AddVersionQueryParameter : IOperationFilter {
public void Apply(Operation operation, OperationFilterContext context) {
var lastControllerVersion = context.ApiDescription.ControllerAttributes()
.OfType<ApiVersionAttribute>()
.Where(apiVer => !apiVer.Deprecated)
.SelectMany(attr => attr.Versions)
.OrderByDescending(ord => ord.GroupVersion)
.ThenBy(ord => ord.MajorVersion)
.ThenBy(ord => ord.MinorVersion)
.FirstOrDefault();
var lastActionVersion = context.ApiDescription.ActionAttributes()
.OfType<ApiVersionAttribute>()
.Where(apiVer => !apiVer.Deprecated)
.SelectMany(attr => attr.Versions)
.OrderByDescending(ord => ord.GroupVersion)
.ThenBy(ord => ord.MajorVersion)
.ThenBy(ord => ord.MinorVersion)
.FirstOrDefault();
if (lastControllerVersion == null && lastActionVersion == null) return;
var versionParameter = new NonBodyParameter() {
Name = "api-version",
In = "query",
Required = false,
Default = lastActionVersion?.ToString() ?? lastControllerVersion?.ToString(), // default version number
Type = "string",
};
if (operation.Parameters == null) {
operation.Parameters = new List<IParameter>();
}
operation.Parameters.Add(versionParameter);
}
}
It takes the max version of controller or action and set a query parameter with that as default value. I don't think that it will work with multiple swagger doc but it could be a start point.
Hope it helps
@kloarubeek, thanks for this issue.
It would be really nice to have this integrated with Swashbuckle.
In general, I would try to avoid solutions that modify the _ApiDescription_ and instead use the Swashbuckle extension points to modify the generated SwaggerDocument to meet your needs. For this particular case, the cleanest approach (IMO) would be a simple DocInclusionPredicate that selects actions by inspecting the controller for _ApiVersionAttributes_. Then, to remove the version parameters and instead set the version in paths, I would use a really simple Operation / Document filter combo as follows:
// Startup.cs
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Version = "v1", Title = "API V1" });
c.SwaggerDoc("v2", new Info { Version = "v2", Title = "API V2" });
c.DocInclusionPredicate((docName, apiDesc) =>
{
var versions = apiDesc.ControllerAttributes()
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
return versions.Any(v => $"v{v.ToString()}" == docName);
});
c.OperationFilter<RemoveVersionParameters>();
c.DocumentFilter<SetVersionInPaths>();
});
// RemoveVersionParameters.cs
public class RemoveVersionParameters : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var versionParameter = operation.Parameters.Single(p => p.Name == "version");
operation.Parameters.Remove(versionParameter);
}
}
// SetVersionInPaths.cs
public class SetVersionInPaths : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Paths = swaggerDoc.Paths
.ToDictionary(
path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
path => path.Value
);
}
}
Check out the MultipleVersions example to these this exact approach in action.
@xperiandri - people implement versioning in many different ways so at this point my stance is to have Swashbuckle provide sufficient extension points, rather than second guessing and building something directly into the framework.
Thanks for this guide and sample. I completely agree.
However RemoveVersionParameters.cs must contain
C#
var versionParameter = operation.Parameters?.SingleOrDefault(p => p.Name == "version");
if (versionParameter != null)
聽 聽 operation.Parameters.Remove(versionParameter);
Because聽agnostic to version聽APIs can exist.
Makes sense
@domaindrivendev,
It works fine when the whole controller has ApiVersion attribute. Anyhow, if I have actions for different API versions, that have MapToApiVersion attribute, it seems that Swagger fails to parse this attribute and distinguish the method, resulting in a error, saying there are multiple actions with the same definition.
Is there a way to get this working?
@TDabasinskas - you'll just have to get a little more creative with the _DocInclusionPredicate_ to support the _MapToApiVersionAttribute_. Hint: Swashbuckle adds an extension method called _GetActionAttributes()_ to the _ApiDescription_ that's passed to the predicate.
@TDabasinskas - food for thought...
options.DocInclusionPredicate((version, actionDescriptor) =>
{
var controllerVersions =
actionDescriptor.ControllerAttributes().OfType
var actionVersions =
actionDescriptor.ActionAttributes().OfType
return controllerVersions.Any(v => $"v{v.ToString()}" == version) &&
(!actionVersions.Any() || actionVersions.Any(v => $"v{v.ToString()}" == version));
})
@AngelVHS Thanks for the nudge in the right direction, I've been having the same issue as well with MaptToApiVersion
I've now got this which seems to be working
swaggerOptions.DocInclusionPredicate((version, apiDescription) =>
{
var actionVersions = apiDescription.ActionAttributes().OfType<MapToApiVersionAttribute>().SelectMany(attr => attr.Versions).ToList();
var controllerVersions = apiDescription.ControllerAttributes().OfType<ApiVersionAttribute>().SelectMany(attr => attr.Versions).ToList();
var controllerAndActionVersionsOverlap = controllerVersions.Intersect(actionVersions).Any();
if(controllerAndActionVersionsOverlap)
{
return false;
}
return controllerVersions.Any(v => $"v{v.ToString()}" == version);
});
Looks strange:
@xperiandri
Given the above I've revised my code to the following
swaggerOptions.DocInclusionPredicate((version, apiDescription) =>
{
var actionVersions = apiDescription.ActionAttributes().OfType<MapToApiVersionAttribute>().SelectMany(attr => attr.Versions);
var controllerVersions = apiDescription.ControllerAttributes().OfType<ApiVersionAttribute>().SelectMany(attr => attr.Versions);
var controllerAndActionVersionsOverlap = controllerVersions.Intersect(actionVersions).Any();
if (controllerAndActionVersionsOverlap)
{
return actionVersions.Any(v => $"v{v.ToString()}" == version);
}
return controllerVersions.Any(v => $"v{v.ToString()}" == version);
});
This code does come with a catch though. Given the MapToAPI example in the versioning documents the Get method (i.e. "Hello world v2!") also gets added to the Version 3.0 Swagger document because both 2.0 and 3.0 attributes are present at a controller level.
That said I've managed to work around it by adding the MapToApiVersion attribute to the Get method as well like this
[ApiVersion("2.0")]
[ApiVersion("3.0")]
[Route("api/v{version:apiVersion}/helloworld")]
public class HelloWorld2Controller : Controller
{
[HttpGet, MapToApiVersion("2.0")]
public string Get() => "Hello world v2!";
[HttpGet, MapToApiVersion("3.0")]
public string GetV3() => "Hello world v3!";
}
How can I specify version to be a digit only but in UI display "Version X"?
@domaindrivendev, could you give and advice?
C#
options.SwaggerDoc("1", new Info
{
Title = "API version 1",
Version = "Version 1",
});
I've pulled the above into a separate library that abstracts all of this detail away to make life easier.
If anyone's interested it's available here
The versioning package is adding support for IApiDescriptionProvider in https://github.com/Microsoft/aspnet-api-versioning/issues/60, so would Swashbuckle just work with no extra code?
As the owner of ASP.NET API Versioning, I can say that Swashbuckle will _almost_ work without any additional work. I'm explicitly avoiding any direct dependencies on Swagger/Swashbuckle just as these libraries wouldn't take direct dependencies on API versioning.
The connection to API versioning will look like: services.AddMvcCore().AddVersionedApiExplorer();. To see how this _magic_ happens, check out VersionedApiDescriptionProvider.cs. Effectively, the versioned API explorer will use the API version and bucketize them into groups using the version metadata. The ApiDescription.GroupName will hold this value. This also means your own custom grouping via [ApiExplorerSettings(GroupName="...")] will be overwritten (in the current design). Since API versions can be interleaved, it's possible that an action will be reported multiple times (which is a problem with some folks current attempts to implement this themselves). From there, Swagger and Swashbuckle will _just work_.
The current sample Startup.cs shows how you'll be able use the new IApiVersionDescriptionProvider service to discover and enumerate all of the possible API version information in your application to build multiple Swagger documents.
The one caveat I've faced so far is how to include the API version parameter. This parameter can take many forms depending how you choose to implement API versioning (query string, header, media type, or a combination). In general, this is very simple to implement with an IOperationFilter. The sample ImplicitApiVersionParameter.cs actually shows a complex scenario with multiple API versioning schemes in a single application.
If any of the folks on the Swagger/Swashbuckle team are interested in how to tighten up this experience out-of-the-box, I'd love to have that conversation. I'm also working with the ASP.NET team. They're already planning on rolling some of the abstractions in to the core platform. I don't know the details yet, but that would certainly make the integration of the two easier. As it stands, I still believe it's possible to link these two projects together without direct coupling given a little careful designing.
I have added the following to my project file...
PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.1.0-beta1"
PackageReference Include="Microsoft.AspNetCore.Mvc.ApiExplorer" Version="1.1.2"
However I get the message...
IMvcCoreBuilder' does not contain a definition for 'AddVersionedApiExplorer' and no extension method 'AddVersionedApiExplorer' accepting a first argument of type 'IMvcCoreBuilder' could be found (are you missing a using directive or an assembly reference?
There is AddApiExplorer() is this wahat I need to use, or is there another assembly or something else I need to do?
Apologies for any confusion due to the cross-repo comment. This support is not yet available. You can track the progress in Issue #60 in the ASP.NET API Versioning repo. I expect to have something ready to publish to NuGet within the week.
The main reason to comment here was to let the interested folks know it was happening and enlist feedback. You can get a sense of how it will all look and come together in the sample in the working topic branch.
I've added full versioning support to the ASP.NET API Boilerplate project template. You can now use dotnet new to create a project and optionally enable or disable Swagger and/or ASP.NET API Versioning (Both options are turned on by default) as well as a dozen other settings.
@RehanSaeed, wow! Looks extremely cool!
It would be nice to make it all work for F# too
@xperiandri Alas my F#-fu is weak and puny. Also, doesn't F# use an alternate framework built on top of MVC. Would accept a PR though if someone is willing.
Well there are a few but they are more theoretical than practical. So ASP.NET Core is the only usable as I see. So I will try to transform templates into it sometime.
Thanks for all your work here guys. Quick question though! Are we still expected to to alter the operation path labels ourselves with a DocumentFilter if we do versioning like /api/v{version}/users or was this something that should be happening automatically using these latest contributions? I managed to get the IApiVersionDescriptionProvider and ImplicitApiVersionParameter stuff working but didn't know if I was missing something else I needed to do.
Also, it looks like there's still an issue with the Operation IDs. Is there a separate issue tracking that?
I'm surprised by the number of people that expect the {version} route parameter to be _auto-magically_ filled in. No one expects /api/users/{id} to somehow fill in {id}. While I suppose it would be convenient to have /api/v{version}/users become /api/v1/users, it is only a convenience. I did set things up in the API explorer to associate the current API version with the API descriptor so that the {version} route parameter will have a default value matching the current version. For any other behavior, you'd have to use a custom DocumentFilter or IOperationFilter to make things behave the way you want. Regardless, all of the pieces are there to make that happen.
The issue with Operation IDs is still there. This was being tracked in issue #333, but was closed. I took a look, commented, and asked that it be reopened; it's bug. The issue isn't related specially to API versioning and can happen in other scenarios (that I demonstrated).
Looking at AutoRest, I believe there's a better approach.
From AutoRest https://github.com/Azure/azure-rest-api-specs/blob/master/documentation/creating-swagger.md
Global parameters Swagger allows for parameters to be defined separately from the operation where they are used. By convention, AutoRest treats global parameter definitions as Client properties. For example, almost all Azure Resource Manager APIs require subscriptionId and api-version. These are defined as global parameters and become properties of the client.
First, add a global parameter to the document:
public class ApiVersionGlobalParameter : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
var apiVersion = swaggerDoc.Info.Version;
swaggerDoc.Parameters = swaggerDoc.Parameters ?? new Dictionary<string, IParameter>();
swaggerDoc.Parameters.Add(
new KeyValuePair<string, IParameter>(
"api-version",
(IParameter)new NonBodyParameter() {
In="query",
Default= apiVersion,
Type="string",
Required = true,
Name= "api-version"
}));
}
}
Then add a $ref parameter on each operation
public class ImplicitApiVersionParameter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var apiVersion = context.ApiDescription.GetApiVersion();
// if the api explorer did not capture an API version for this operation
// then the action must be API version-neutral; there's nothing to add
if (apiVersion == null)
{
return;
}
var parameters = operation.Parameters;
if (parameters == null)
{
operation.Parameters = parameters = new List<IParameter>();
}
// consider the url path segment parameter first
var parameter = parameters.SingleOrDefault(p => p.Name == "api-version");
if (parameter == null)
{
parameter = new NonBodyParameter()
{
Ref = "#/parameters/api-version"
};
parameters.Add(parameter);
}
else if (parameter is NonBodyParameter pathParameter)
{
pathParameter.Default = apiVersion.ToString();
}
parameter.Description = "The requested API version";
}
}
The ability to reference a global parameter on a operation parameter has just been merged on Swashbuckle: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/403
I agree; there is definitely a better approach. Sometimes you just need a break from things to let ideas brew. My first priority was to get something out that folks can play with.
I've come to realize that all that is needed is a way to dynamically add the parameters. Originally, I was thinking that this could be done by inferring different IApiVersionReader implementations. I concluded that was a bad idea. After thinking about it some more, I think what really needs to happen is refactor the IApiVersionReader to support populating these parameters. Since this interface is responsible for reading an API version, it should also know how to document the way that it does it. I'm close to the 1.1 release, but I'll see if I can't sneak that in.
While your proposal is feasible, it misses quite a few other scenarios. For one, it's possible that a single API versioning methodology might support multiple values. For example, Azure is transitioning to api-version as part of the official REST guidelines, but many services still support the legacy x-ms-version header. It's possible that a service might support multiple headers. Even more complex, IApiVersionReader instances can be composed and aggregated. For example, a service author might allow using both the query string and header approaches.
Ultimately, I think it gets much simpler if you just _ask_ the IApiVersionReader to provide this documentation. Something like Options.ApiVersionReader.AddParameterDescriptions or Options.ApiVersionReader.DescribeParameters. In terms of required versus optional, I think it's reasonable to assume that the first defined parameter is always required and any other are optional; at least, out-of-the-box.
I can't commit to exactly when this might happen, but you can almost be assured that it will. I didn't like the idea of having to solve gap this with a custom IOperationFilter, but it was the best solution at the time. Now that I've thought about it more (as you can probably tell), I think there's a way to make it better. I'd love to get that out in the next release. We'll see. Feel free to open an issue to track this on the API Versioning repo. With this feature/capability in place, I don't believe any other customization of Swagger/Swashbuckle will be required for out-of-the-box support.
I agree with you as well. Need to look at the broader use cases here.
I just want to stress that ensuring a better integration with AutoRest is a nice thing to do, and my comment was more in the sense that AutoRest now makes client parameters only from global parameters on swagger, and global parameters on swagger need to be add as $ref on operations, which is not possible out-of-the-box right now.
@israellot and anyone else following, I submitted PR 140 over at API Versioning to address automatically exploring API version parameters. Unfortunately, I uncovered a couple of issues in Swashbuckle (#412), which prevent things from lighting up automatically. I've submitted PR #413 to resolve them, but it may take some time before they are published. In the meantime, if you want see how things have been simplified, you can preview SwaggerDefaultValues.cs, which used to be ImplicitApiVersionParameter.cs. Feel free to comment more about these changes over at API Versioning.
Looks nice. So do you expect it to be used until PR is merged?
Swashbuckle PR #413 needs to be merged and published. I'll be merging the changes for PR140 over in API Versioning soon; probably later today. PR140 gets the API Versioning in place to make this possible, but without #413 here in Swashbuckle, it's not possible for things to happen _auto-magically_. Once the Swashbuckle changes are in place, I'll update the samples and remove SwaggerDefaultValues.cs completely. ;)
Looks like the fix that @commonsensesoftware was working on has stalled, is there anything that I can do to help?
@garrmark the tests were broken, but have now been fixed (as I understand it). I guess that doesn't trigger re-evaluation by AppVeyor. Perhaps the changes have stalled because it seems the build is showing broken from the last run. There should be no further changes required on my side. Do you know how to make AppVeyor re-evaluate the PR changes?
Push another commit to trigger AppVeyor..
What's the defacto way of doing this then?
@alexdresko, I can't say what the hold up is. The PR was out-of-sync again, but I just updated it. It should be back to the _ready to merge_ state as soon as the CI run completes.
@Mardoxx, if you're asking what the de facto integration between Swagger and ASP.NET API Versioning is, then it is one of the API Versioning API Explorer packages (Swashbuckle uses the API Explorer under the hood). There are different packages depending on whether you're using Web API, OData, or ASP.NET Core. All the packages are listed on the landing page.
A lot of people have been asking me about route template substitutions lately. It seems they have been asking here as well. This is possible in the API Versioning API Explorer today, but you have to extend the VersionedApiExplorer to do so. There are some examples of how to do this in some existing issues. Since this seems to be such a common ask, I've just queued up a feature enhancement to provide this out-of-the-box (see #247).
@rh072005 thanks muchly for your code. The ActionAttributes() and ControllerAttributes() functions are now obsolete, so to bring the code up to date you can accomplish the same thing like this:
c.DocInclusionPredicate((version, apiDescription) =>
{
apiDescription.TryGetMethodInfo(out MethodInfo methodinfo);
var actionVersions = methodinfo.GetCustomAttributes<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var controllerVersions = methodinfo.DeclaringType.GetCustomAttributes<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var controllerAndActionVersionsOverlap = controllerVersions.Intersect(actionVersions).Any();
var versions = controllerAndActionVersionsOverlap ? actionVersions : controllerVersions;
return versions.Any(v => $"v{v.ToString()}" == version);
});
@rocklan thanks for picking this up. I've actually made a few changes to that code since and pulled it into a separate library.
You can find the project at https://github.com/rh072005/SwashbuckleAspNetVersioningShim
If you spot anything in there that doesn't look quite if you open an issue (or PR) and I'll get right on it.
@rocklan and @rh072005, while your code will work for your specific scenarios that's not the _right_ way to get this information. API versioning doesn't care about attributes - it cares about IApiVersionProvider. Attributes are only one way this information can be provided. API Versioning has now long-supported an API version-aware API Explorer. This will do all of the API version discovery and API action collation. You only need also reference the API Versioning API Explorer NuGet package. A sample project is available here. Additional information is provided on the wiki.
I'm happy to answer any specific questions regarding API versioning in its home repo. There is nothing on the Swashbuckle/Swagger side required to change to make things light up.
Thanks
@commonsensesoftware yeah I moved the code in the nuget package over to use API Explorer when it was released so none of that code above is still there. You're spot on when you say it doesn't support all of the ways of versioning the API, currently it's only attribute and query string. Initially the nuget package was just about abstracting away the boilerplate but now there's not really the need it IMO (I wasn't expecting people to still be using it). I'm still maintaining it for anyone that wants to use it but I'll add the links you've put above on the readme of my project to point people that way of doing things.
Most helpful comment
In general, I would try to avoid solutions that modify the _ApiDescription_ and instead use the Swashbuckle extension points to modify the generated SwaggerDocument to meet your needs. For this particular case, the cleanest approach (IMO) would be a simple DocInclusionPredicate that selects actions by inspecting the controller for _ApiVersionAttributes_. Then, to remove the version parameters and instead set the version in paths, I would use a really simple Operation / Document filter combo as follows:
Check out the MultipleVersions example to these this exact approach in action.
@xperiandri - people implement versioning in many different ways so at this point my stance is to have Swashbuckle provide sufficient extension points, rather than second guessing and building something directly into the framework.