我们希望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
属性。隐藏方法一切正常。
问题:我找不到完全移除控制器的方法。我想我的问题是:如果不必设置必须在编译时设置的[ApiExplorerSettings(IgnoreApi = true)]
属性,我如何删除控制器以使其不显示在SwaggerUI中?
我尝试过的:
- 当满足隐藏控制器的条件时,让
SwaggerUIVisibilityAttribute
扩展ApiExplorerSettingsAttribute
并在过滤器中设置IgnoreApi = true
。结果:它仍在显示中(我想我已经太迟了( - 在
SwaggerUIVisibilityFilter.Apply
中,从DocumentFilterContext.ApiDescriptions
中删除控制器。结果:不可能,因为此属性是仅获取的IEnumerable
这很简单。将以下属性置于要隐藏的任何操作或控制器之上:
[ApiExplorerSettings(IgnoreApi = true)]
我在这篇博客文章中找到了解决方案。感谢@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));
})