在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属性。隐藏方法一切正常。

问题:我找不到完全移除控制器的方法。我想我的问题是:如果不必设置必须在编译时设置的[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));
})

最新更新