asp.net-core - 无法使用 Swashbuckle 创建多个 OpenApi 规范
问题描述
我正在使用 Asp.Net Boilerplate / Asp.Net Zero 构建解决方案
我在 Startup.cs 中创建了两个 OpenApi 规范(HostApiv1
和TenantApiv1
),如下所示:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("HostApiv1", new Info { Title = "Host API v1", Version = "v1" });
options.SwaggerDoc("TenantApiv1", new Info { Title = "Tenant API v1", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.IgnoreObsoleteActions();
options.IgnoreObsoleteProperties();
options.OrderActionsBy((apiDesc) => $"{apiDesc.RelativePath}");
options.DescribeAllEnumsAsStrings();
});
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint(_appConfiguration["App:HostApiSwaggerEndPoint"], "Host API v1");
options.SwaggerEndpoint(_appConfiguration["App:TenantApiSwaggerEndPoint"], "Tenant API v1");
//...
});
但是,当我用 装饰我的 AppService 类时[ApiExplorerSettings(GroupName = "HostApiv1")]
,分组将被忽略,并且标记(AppService 控制器)及其所有操作(操作/方法)仍然出现在两个文档下。
知道出了什么问题,或者我该如何调试它?
解决方案
Swashbuckle 依赖于ApiExplorer
,并且该ApiExplorer
属性的使用将我们限制为每个控制器/操作仅指定一个组名。ABP 服务代理是通过 NSwag 为 Angular 项目生成的,似乎在这个过程中,依赖关系被破坏了。
解决方法是为应用服务控制器或操作创建一个自定义Attribute
来分隔一个或多个组名,然后在DocInclusionPredicateFunction
选项中使用反射来检索操作或其包含控制器的组名。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class SwaggerDocAttribute: Attribute
{
public SwaggerDocAttribute(params string[] includeInDocuments)
{
IncludeInDocuments = includeInDocuments;
}
public string[] IncludeInDocuments { get; }
}
options.DocInclusionPredicate((docName, apiDesc) =>
{
if (!apiDesc.ActionDescriptor.IsControllerAction())
{
return false;
}
apiDesc.TryGetMethodInfo(out MethodInfo methodInfo);
var actionDocs = methodInfo.GetCustomAttributes<SwaggerDocAttribute>()
.SelectMany(a => a.IncludeInDocuments);
var controllerDocs = methodInfo.DeclaringType.GetCustomAttributes<SwaggerDocAttribute>()
.SelectMany(a => a.IncludeInDocuments);
switch (docName)
{
case "HostApiv1":
return apiDesc.GroupName == null ||
actionDocs.Contains("HostApiv1") ||
controllerDocs.Contains("HostApiv1");
case "TenantApiv1":
return apiDesc.GroupName == null ||
actionDocs.Contains("TenantApiv1") ||
controllerDocs.Contains("TenantApiv1");
default:
return true;
}
});
用法
[DisableAuditing]
[AbpAuthorize(AppPermissions.HostSpecific.Dashboard.Access)]
//[ApiExplorerSettings(GroupName = "HostApiv1")] // <== Don't use this
[SwaggerDoc("HostApiv1")] // <== Use this in stead
public class MyDemoAppService : ZenDetectAppServiceBase, IHostDashboardAppService
{
//...
}
推荐阅读
- ide - Windows 10 中的 Free Pascal IDE (FP) 行为很奇怪
- jsf - 表单验证的立即属性在 JSF 中产生意外结果
- java - 以下java函数没有将数据插入数据库,
- javascript - 来自 javascript 的 asp.net MVC 调用控制器
- asp.net-web-api - 如何增加 .net core 中的请求限制?
- android - 如何在使用 React Native 导航时将推送通知集成到 React Native 中
- json - 火花,蜂巢;系统设计问题每天处理 2TB
- php - onerror 显示无 - php ($.row['img'])
- mips - MIPS 写数字列表的练习
- php - 如何过滤数组中的值