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)] 属性?

我尝试过的:

我在 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)]