Hide/show SwaggerUI 中的控制器(可配置)
Hide/show controllers in SwaggerUI (configurable)
我们希望由 Swashbuckle 生成的 SwaggerUI 在调试时以及我们的测试环境中显示所有控制器和方法,但在集成和生产环境中隐藏一些控制器和方法。请注意,隐藏的 controllers/methods 将在所有场景中发挥作用,但不会记录在 SwaggerUI 中。
为此,我应用了 here.
中描述的主体
这导致以下代码:
属性定义:
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
中移除控制器。结果:不可能,因为此 属性 是一个仅获取 IEnumerable
我在 this blog post 中找到了解决方案。感谢@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));
})
很简单。
将以下属性放在要隐藏的任何操作或控制器上方:
[ApiExplorerSettings(IgnoreApi = true)]
我们希望由 Swashbuckle 生成的 SwaggerUI 在调试时以及我们的测试环境中显示所有控制器和方法,但在集成和生产环境中隐藏一些控制器和方法。请注意,隐藏的 controllers/methods 将在所有场景中发挥作用,但不会记录在 SwaggerUI 中。
为此,我应用了 here.
中描述的主体这导致以下代码:
属性定义:
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
中移除控制器。结果:不可能,因为此 属性 是一个仅获取IEnumerable
我在 this blog post 中找到了解决方案。感谢@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));
})
很简单。 将以下属性放在要隐藏的任何操作或控制器上方:
[ApiExplorerSettings(IgnoreApi = true)]