Swashbuckle and Microsoft.AspNetCore.Mvc.Versioning are friends at the moment. It works well. I just created a test project in VS2017 and checked how it works.
First enable these two nuget packages:
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.2.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
Set everything up in Startup.cs
(read my comments):
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // Configure versions services.AddApiVersioning(o => { o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = new ApiVersion(1, 0); }); // Configure swagger services.AddSwaggerGen(options => { // Specify two versions options.SwaggerDoc("v1", new Info() { Version = "v1", Title = "v1 API", Description = "v1 API Description", TermsOfService = "Terms of usage v1" }); options.SwaggerDoc("v2", new Info() { Version = "v2", Title = "v2 API", Description = "v2 API Description", TermsOfService = "Terms of usage v2" }); // This call remove version from parameter, without it we will have version as parameter // for all endpoints in swagger UI options.OperationFilter<RemoveVersionFromParameter>(); // This make replacement of v{version:apiVersion} to real version of corresponding swagger doc. options.DocumentFilter<ReplaceVersionWithExactValueInPath>(); // This on used to exclude endpoint mapped to not specified in swagger version. // In this particular example we exclude 'GET /api/v2/Values/otherget/three' endpoint, // because it was mapped to v3 with attribute: MapToApiVersion("3") options.DocInclusionPredicate((version, desc) => { var versions = desc.ControllerAttributes() .OfType<ApiVersionAttribute>() .SelectMany(attr => attr.Versions); var maps = desc.ActionAttributes() .OfType<MapToApiVersionAttribute>() .SelectMany(attr => attr.Versions) .ToArray(); return versions.Any(v => $"v{v.ToString()}" == version) && (maps.Length == 0 || maps.Any(v => $"v{v.ToString()}" == version)); }); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint($"/swagger/v2/swagger.json", $"v2"); c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"v1"); }); app.UseMvc(); }
There are two classes that do the trick:
public class RemoveVersionFromParameter : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { var versionParameter = operation.Parameters.Single(p => p.Name == "version"); operation.Parameters.Remove(versionParameter); } } public class ReplaceVersionWithExactValueInPath : 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 ); } }
RemoveVersionFromParameter
removes this text field from the swagger user interface:
ReplaceVersionWithExactValueInPath
change this:
:
The controller class is as follows:
[Route("api/v{version:apiVersion}/[controller]")] [ApiVersion("1")] [ApiVersion("2")] public class ValuesController : Controller { // GET api/values [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 [HttpGet("{id}")] public string Get(int id) { return "value"; } // POST api/values [HttpPost] public void Post([FromBody]string value) { } // PUT api/values/5 [HttpPut("{id}")] public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 [HttpDelete("{id}")] public void Delete(int id) { } [HttpGet("otherget/one")] [MapToApiVersion("2")] public IEnumerable<string> Get2() { return new string[] { "value1", "value2" }; } /// <summary> /// THIS ONE WILL BE EXCLUDED FROM SWAGGER Ui, BECAUSE v3 IS NOT SPECIFIED. 'DocInclusionPredicate' MAKES THE /// TRICK /// </summary> /// <returns></returns> [HttpGet("otherget/three")] [MapToApiVersion("3")] public IEnumerable<string> Get3() { return new string[] { "value1", "value2" }; } }
Code: https://gist.github.com/Alezis/bab8b559d0d8800c994d065db03ab53e