我遇到的問題與有關 Swagger UI 中多個 API 檔案的其他問題略有不同。
我.json按預期生成了兩個檔案,UI 的右上角有一個下拉選單,允許我在 v1 檔案和 v2 檔案之間切換。
這是我的問題:v1 檔案顯示 v1 API 的一個可用操作。但是,v2 檔案顯示了 v1 和 v2 的可用操作。
這是我的startup.cs檔案中的完整代碼:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using netCoreV3_1ApiStarter.Entities;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Versioning;
namespace netCoreV3_1ApiStarter
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
#region API Versioning
services.AddApiVersioning(c =>
{
c.DefaultApiVersion = new ApiVersion(1, 0);
c.AssumeDefaultVersionWhenUnspecified = true;
c.ReportApiVersions = true;
c.ApiVersionReader = new UrlSegmentApiVersionReader();
});
#endregion
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = $"{Configuration.GetSection("ApplicationName").Value} API",
Version = "v1",
Description = $"API v1 methods available for the {Configuration.GetSection("ApplicationName").Value} system",
Contact = new OpenApiContact
{
Email = "[email protected]",
Name = "Nunya",
Url = new System.Uri("http://www.apple.com")
}
});
c.SwaggerDoc("v2", new OpenApiInfo
{
Title = $"{Configuration.GetSection("ApplicationName").Value} API",
Version = "v2",
Description = $"API v2 methods available for the {Configuration.GetSection("ApplicationName").Value} system",
Contact = new OpenApiContact
{
Email = "[email protected]",
Name = "Nunya",
Url = new System.Uri("http://www.apple.com")
}
});
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
c.DocInclusionPredicate((docName, apiDesc) => apiDesc.GroupName == docName);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", $"{Configuration.GetSection("ApplicationName").Value} API v1");
c.SwaggerEndpoint("/swagger/v2/swagger.json", $"{Configuration.GetSection("ApplicationName").Value} API v2");
c.RoutePrefix = string.Empty;
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
我將我的控制器按 API 版本分成子檔案夾,以嘗試組織和防止命名空間沖突等。
v1WeatherForecastController.cs檔案:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace netCoreV3_1ApiStarter.Controllers.v1
{
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "v1")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
而且,我的 v2 WeatherForecastController.cs:
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace netCoreV3_1ApiStarter.Controllers.v2
{
[ApiVersion("2.0")]
[ApiExplorerSettings(GroupName = "v2")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class WeatherForecastController : ControllerBase
{
// GET: api/<WeatherForecastController>
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<WeatherForecastController>/5
[HttpGet("{id}")]
public string Get(int id)
{
return $"API v2 {id}";
}
// POST api/<WeatherForecastController>
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/<WeatherForecastController>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/<WeatherForecastController>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
關于我缺少讓 v1 螢屏顯示可用的 v1 操作和 v2 螢屏顯示可用的 v2 操作的任何建議?
2021 年 10 月 21 日編輯:修復了第二個 SwaggerDoc 物件定義中的拼寫錯誤。在應該參考 v2 時錯誤地參考了 v1。但是,性能沒有區別。
uj5u.com熱心網友回復:
根據您的要求,切換V2版本時是不是只顯示了v2的部分API?
你可以這樣做:
使用的版本
ASP.NET Core 3.1
Swashbuckle.AspNetCore: 5.4.1
首先我創建了兩個版本的檔案夾和控制器:

因此,每個控制器的命名空間對應其檔案夾,如下所示:
V1版本
namespace WebApplication129.Controllers.V1
{
[ApiController]
[Route("api/v1/[controller]")]
public class HomeController : ControllerBase
{
[Route("test")]
[HttpGet]
public string Test()
{
return "v1 test";
}
}
}
V2版本
namespace WebApplication129.Controllers.V2
{
[ApiController]
[Route("api/v2/[controller]")]
public class HomeController : ControllerBase
{
[Route("test")]
[HttpGet]
public string Test()
{
return "v2 test";
}
}
}
然后創建一個協議通知Swagger,這樣我們就可以控制Swagger如何生成Swagger檔案,從而控制UI。
創建以下類:
public class GroupingByNamespaceConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
var controllerNamespace = controller.ControllerType.Namespace;
var apiVersion = controllerNamespace.Split(".").Last().ToLower();
if (!apiVersion.StartsWith("v")) { apiVersion = "v1"; }
controller.ApiExplorer.GroupName = apiVersion;
}
}
我們所做的是根據其命名空間的最后一段對控制器進行分組。因此,命名空間以 v1 結尾的控制器將被歸為“v1”,以 v2 結尾的控制器將歸為“v2”,以此類推。
Now we must apply the convention. For that we go to AddControllers in ConfigureServices and add the convention:
services.AddControllers(options =>
{
options.Conventions.Add(new GroupingByNamespaceConvention());
});
The final complete startup.cs configuration is as follows:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System;
using WebApplication129.Controllers.conf;
namespace WebApplication129
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.Conventions.Add(new GroupingByNamespaceConvention());
});
services.AddSwaggerGen(config =>
{
var titleBase = "Test API";
var description = "This is a Web API for Test operations";
var TermsOfService = new Uri("https://xxxxxx");
var License = new OpenApiLicense()
{
Name = "Test"
};
var Contact = new OpenApiContact()
{
Name = "Test",
Email = "[email protected]",
Url = new Uri("https://xxxxxx")
};
config.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = titleBase " v1",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
config.SwaggerDoc("v2", new OpenApiInfo
{
Version = "v2",
Title = titleBase " v2",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(config =>
{
config.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
config.SwaggerEndpoint("/swagger/v2/swagger.json", "v2");
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Visit url: https://localhost:yourport/swagger/index.html
Result:

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/329749.html
