c# - 在 SwaggerUI 中隐藏/显示控制器(可配置)
问题描述
我们希望由 Swashbuckle 生成的 SwaggerUI 在调试时以及在我们的测试环境中显示所有控制器和方法,但在集成和生产环境中隐藏一些。请注意,隐藏的控制器/方法在所有场景中都可以使用,但不会在 SwaggerUI 中记录。
为此,我应用了此处描述的主体。
这导致以下代码:
属性定义:
using System;
using Microsoft.AspNetCore.Mvc;
namespace Test
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class SwaggerUIVisibilityAttribute : ApiExplorerSettingsAttribute
{
public SwaggerUIVisibilityAttribute(SwaggerUIVisibility visibility)
{
Visibility = visibility;
}
public SwaggerUIVisibility Visibility { get; }
}
public enum SwaggerUIVisibility
{
Debug,
Internal,
Public
}
}
过滤器(正在进行中):
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
namespace Test
{
public class SwaggerUIVisibilityFilter : IDocumentFilter
{
#region Private Fields
private readonly SwaggerUIVisibility _swaggerUIVisibility;
#endregion
#region Constructors
public SwaggerUIVisibilityFilter(SwaggerUIVisibility swaggerUIVisibility)
{
_swaggerUIVisibility = swaggerUIVisibility;
}
#endregion
#region Public Methods
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var apiDescription in context.ApiDescriptions)
{
var controllerActionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor;
var controllerSwaggerUIVisibilityAttribute = controllerActionDescriptor?.ControllerTypeInfo
.GetCustomAttributes<SwaggerUIVisibilityAttribute>()
.SingleOrDefault();
var methodSwaggerUIVisibilityAttribute = controllerActionDescriptor?.MethodInfo
.GetCustomAttributes<SwaggerUIVisibilityAttribute>()
.SingleOrDefault();
var mustHideController = MustHide(controllerSwaggerUIVisibilityAttribute?.Visibility);
if (mustHideController && controllerSwaggerUIVisibilityAttribute != null)
{
// TODO: Hide controller. How?
//controllerSwaggerUIVisibilityAttribute.IgnoreApi = true;
}
var mustHideMethod = MustHide(methodSwaggerUIVisibilityAttribute?.Visibility);
if (mustHideMethod)
{
var route = "/" + apiDescription.RelativePath.TrimEnd('/');
swaggerDoc.Paths.Remove(route);
}
}
}
#endregion
#region Private Methods
private bool MustHide(SwaggerUIVisibility? visibility)
{
return visibility switch
{
SwaggerUIVisibility.Debug => _swaggerUIVisibility != SwaggerUIVisibility.Debug,
SwaggerUIVisibility.Internal => _swaggerUIVisibility != SwaggerUIVisibility.Debug
&& _swaggerUIVisibility != SwaggerUIVisibility.Internal,
SwaggerUIVisibility.Public => _swaggerUIVisibility != SwaggerUIVisibility.Debug
&& _swaggerUIVisibility != SwaggerUIVisibility.Internal
&& _swaggerUIVisibility != SwaggerUIVisibility.Public,
_ => false
};
}
#endregion
}
}
注册Startup
:
services.AddSwaggerGen(options =>
{
[...]
options.DocumentFilter<SwaggerUIVisibilityFilter>(SwaggerUIVisibility.Internal);
});
SwaggerUIVisibilityAttribute
可以为类和方法设置属性。一切都可以很好地隐藏方法。
问题:我找不到完全移除控制器的方法。我想我的问题是:如何删除一个控制器而不显示在 SwaggerUI 中,而不必设置[ApiExplorerSettings(IgnoreApi = true)]
必须在编译时设置的属性?
我试过的:
- 当满足隐藏控制器的条件时,让
SwaggerUIVisibilityAttribute
扩展ApiExplorerSettingsAttribute
和设置在过滤器中。IgnoreApi = true
结果:它仍在显示(我想我在管道中为时已晚) - 在
SwaggerUIVisibilityFilter.Apply
中,从 中移除控制器DocumentFilterContext.ApiDescriptions
。结果:不可能,因为这个属性是一个 get onlyIEnumerable
解决方案
我在这篇博文中找到了解决方案。感谢@juunas
为了解决我的问题,我保留了最初问题中的代码以隐藏控制器方法。为了隐藏控制器,我实现了一个IActionModelConvention
:
namespace Test
{
/// <summary>
/// Shows/hides controllers in SwaggerUI. Specify the <see cref="SwaggerUIVisibility"/> in the constructor, when instantiating this class; only methods having a equal or higher visibility will be displayed.<br/>
/// Visibility order: <see cref="SwaggerUIVisibility.Public"/> > <see cref="SwaggerUIVisibility.Internal"/> > <see cref="SwaggerUIVisibility.Debug"/>
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.Mvc.ApplicationModels.IActionModelConvention" />
public class SwaggerUIControllerVisibilityConvention : IActionModelConvention
{
#region Private Fields
private readonly SwaggerUIVisibility _swaggerUIVisibility;
#endregion
#region Constructors
public SwaggerUIControllerVisibilityConvention(SwaggerUIVisibility swaggerUIVisibility)
{
_swaggerUIVisibility = swaggerUIVisibility;
}
#endregion
#region Public Methods
public void Apply(ActionModel action)
{
var controllerSwaggerUIVisibilityAttribute = action.Controller
.Attributes
.OfType<SwaggerUIVisibilityAttribute>()
.SingleOrDefault();
action.ApiExplorer.IsVisible = _swaggerUIVisibility.GetIsVisible(controllerSwaggerUIVisibilityAttribute?.Visibility);
}
#endregion
}
}
并且也注册Startup
了
services.AddControllers(options =>
{
[...]
options.Conventions.Add(new SwaggerUIControllerVisibilityConvention(apiConfiguration.SwaggerUIVisibility));
})
推荐阅读
- url - 两个收件人的 DocuSign Powerform URL 参数
- python - pmdarima 将对象分配给 auto_arima 输出
- qt - 在 qt 地图中使用 tileserver-gl 主机
- amazon-web-services - 我可以使用 S3 托管图像,并在我的 EC2 网站上使用它们吗?
- swift - Swift 中的 UiSearchBar 到 UiCollectionView
- ruby-on-rails - Rails 对空路径的约定是什么?
- javascript - 如何避免使用“回调地狱”并转向 Promises?
- mysql - MySQL 特定时间的日期时间值不正确
- reactjs - Gatsby 代理到具有相同前缀的多个后端
- python - Applescript 无法获取 Python 调用的返回