在提出解决方案之前,让我先说明几点:
- 上面的 YouTube 视频和 @abdusco 在他们看来提供了他们自己的 API 版本控制方法,但问题是关于 ASP.NET Core API Versioning
- 虽然未指定,但我假设您没有按 URL 段进行版本控制
- 默认的 OpenAPI/Swagger UI 只有一个枢轴点(例如组),您可以在下拉列表中选择它
- OpenAPI/Swagger 文档必须具有唯一的 URL,这意味着您不能在同一个文档中拥有多个 API,除非您按 URL 段进行版本控制(最差的选择;最少的 RESTful)
-
Swagger,我猜你的意思是 Swashbuckle。 Swashbuckle OpenAPI 生成器使用
ApiDescription.GroupName 在每个组的单个文档中整理 API,映射到 UI 中的下拉列表。改变这种行为是可能的,但并非易事。
- API 版本控制的 API Explorer 扩展的默认行为将
ApiDescription.GroupName 设置为格式化的 API 版本值,如果没有另外设置,以便 API 按版本分组。在4.1 之前,[ApiExplorerSettings(GroupName="...")] 被忽略并覆盖。
归根结底,您需要两个分组维度:类别和API版本。不幸的是,API Explorer、OpenAPI/Swagger UI 和 Swashbuckle 本质上只支持其中一种。开箱即用不支持任何形式的层次结构。有几种方法可以解决这个问题:
- 将
group name 和API version 连接为一个维度
- 创建一个 Swashbuckle 扩展(例如:IOOperationFilter)为特定组添加 OpenAPI 标记。然后可以更改 UI 以根据这些标签添加第二个下拉列表以进行过滤,或者标签可用于整理组(想想 Expander 控件)。
- 按 URL 段版本,生成单个 OpenAPI 文档,以您想要的方式更新
GroupName(此方法不推荐)
可能还有更多选择,但这些是最明智的。虽然它可能不是您所希望的,但考虑到使用的限制,#3 是最直接实施的方法。它看起来像这样:
public class SubgroupDescriptionProvider : IApiDescriptionProvider
{
private readonly IOptions<ApiExplorerOptions> options;
public SubgroupDescriptionProvider(IOptions<ApiExplorerOptions> options)
=> this.options = options;
// Execute after DefaultApiVersionDescriptionProvider.OnProvidersExecuted
public int Order => -1;
public void OnProvidersExecuting(ApiDescriptionProviderContext context) { }
public void OnProvidersExecuted(ApiDescriptionProviderContext context)
{
var format = options.Value.GroupNameFormat;
var culture = CultureInfo.CurrentCulture;
var results = context.Results;
var newResults = new List<ApiDescription>(capacity: results.Count);
for (var i = 0; i < results.Count; i++)
{
var result = results[i];
var apiVersion = result.GetApiVersion();
var versionGroupName = apiVersion.ToString(format, culture);
// [ApiExplorerSettings(GroupName="...")] was NOT set so
// nothing else to do
if (result.GroupName == versionGroupName)
{
continue;
}
// must be using [ApiExplorerSettings(GroupName="...")] so
// concatenate it with the formatted API version
result.GroupName += " " + versionGroupName;
// optional: add version grouping as well
// note: this works because the api description will appear in
// multiple, but different, documents
var newResult = result.Clone();
newResult.GroupName = versionGroupName;
newResults.Add(newResult);
}
newResults.ForEach(results.Add);
}
}
然后您使用以下代码向 DI 注册:
services.TryAddEnumerable(
ServiceDescriptor.Transient<IApiDescriptionProvider, SubgroupDescriptionProvider>());
如果您使用两组分组,那么您将获得多个 OpenAPI 文档。
按 API 版本(默认)
├─ v1
│ ├─ /utility
│ └─ /not-utility
└─ v2
├─ /utility
└─ /not-utility
按组名 + API 版本
├─ Utilities v1
│ └─ /utility
├─ Not Utilities v1
│ └─ /not-utility
├─ Utilities v2
│ └─ /utility
└─ Not Utilities v2
└─ /not-utility
如果您的版本控制策略类似于N-2,那么列表应该是合理的。它是group * version 的产品,因此列表将取决于您最终拥有多少组和版本。
拥有一个真正的二维层次结构应该在技术上是可行的,但我从来没有做过,也不知道有人愿意付出努力来实现它。解决方案将非常具体地适用于您的 API 集。