We would like SwaggerUI, which is being generated by Swashbuckle, to show all controllers and methods when debugging as well as on our test environment, but hide some on integration and production environments. Note that the hidden controllers/methods will be functional in all scenarios but won't be documented in SwaggerUI.
To do this I've applied the principal described here.
Which results in following code:
Attribute definition:
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
}
}
Filter (work in progress):
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
}
}
Registration in Startup:
services.AddSwaggerGen(options =>
{
[...]
options.DocumentFilter<SwaggerUIVisibilityFilter>(SwaggerUIVisibility.Internal);
});
The SwaggerUIVisibilityAttribute attribute can be set for classes as well as methods. Everything works fine to hide methods.
Issue: I couldn't find a way to remove the controller entirely.
I think my question is: How can I remove a controller to NOT show up in SwaggerUI without having to set the [ApiExplorerSettings(IgnoreApi = true)] attribute, which has to be set at compile time?
What I've tried:
SwaggerUIVisibilityAttribute extend ApiExplorerSettingsAttribute and set IgnoreApi = true in the filter when the condition to hide the controller is met. Result: It is still being displayed (I guess I'm too late in the pipeline)SwaggerUIVisibilityFilter.Apply, remove the controller from DocumentFilterContext.ApiDescriptions. Result: Not possible as this property is a get only IEnumerableIt's simple. Put the following attribute above any action or controller you want to hide:
[ApiExplorerSettings(IgnoreApi = true)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With