不要在 Swashbuckle (Swagger) 中显示端点

Don't show endpoints in Swashbuckle (Swagger)

我在 SwaggerUI 中遇到显示端点问题。 例如

[ApiVersion("5.0")]
[RoutePrefix("mobile/v{version:apiVersion}/persons")]
public class LessonController : ApiController
{

 -------------------------------------

    [HttpGet]
    [Route("{personId}/groups/{groupId}/lessons/{lessonId}/lessonDetails")]
    public LessonDetailsModel LessonDetails(long personId, long groupId, long lessonId)
    {
       ----------------------------------

它的端点不显示,但如果我将 RoutePrefix 更改为

 [RoutePrefix("mobile/v{version:apiVersion}/persons1")]

端点展示

更新: Swagger配置

 GlobalConfiguration.Configuration
            .EnableSwagger("mobile/swagger/docs/{apiVersion}", c => {
                  c.MultipleApiVersions(
                    ResolveVersionSupportByRouteConstraint,
                    (vc) =>
                    {
                        vc.Version("v5.0", "Api version 5");
                        vc.Version("v4.0", "Api version 4");
           ------------------------------------------------------
                    });

                c.UseFullTypeNameInSchemaIds();
                c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                c.OperationFilter<RemoveVersionParameters>();
                c.OperationFilter<InjectCustomApiParameters>();
                c.DocumentFilter<SetVersionInPaths>();
                c.IncludeXmlComments(Path.ChangeExtension($"{Assembly.GetExecutingAssembly().GetName().CodeBase}", ".xml"));
            })
            .EnableSwaggerUi("mobile/swagger/ui/{*assetPath}", c => {
                c.DocumentTitle("Mobile Api Swagger");
                c.DisableValidator();
                c.EnableDiscoveryUrlSelector();
            });

我找到了解决问题的方法。我实现了 IApiExplorer。

public class VersionedApiExplorer : IApiExplorer
{
    private readonly IApiExplorer _innerApiExplorer;
    private readonly HttpConfiguration _configuration;
    private readonly Lazy<Collection<ApiDescription>> _apiDescriptions;
    private MethodInfo _apiDescriptionPopulator;

    public VersionedApiExplorer(IApiExplorer apiExplorer, HttpConfiguration configuration)
    {
        _innerApiExplorer = apiExplorer;
        _configuration = configuration;
        _apiDescriptions = new Lazy<Collection<ApiDescription>>(Init);
    }

    public Collection<ApiDescription> ApiDescriptions => _apiDescriptions.Value;

    private Collection<ApiDescription> Init()
    {
        var descriptions = _innerApiExplorer.ApiDescriptions;

        var controllerSelector = _configuration.Services.GetHttpControllerSelector();
        var controllerMappings = controllerSelector.GetControllerMapping();

        var flatRoutes = FlattenRoutes(_configuration.Routes).ToList();
        var result = new Collection<ApiDescription>();

        foreach (var description in descriptions)
        {
            result.Add(description);

            if (controllerMappings == null || !description.Route.Constraints.Any()) continue;
            var matchingRoutes = flatRoutes.Where(r =>
                r.RouteTemplate == description.Route.RouteTemplate && r != description.Route);

            foreach (var route in matchingRoutes)
                GetRouteDescriptions(route, result);
        }

        return result;
    }

    private void GetRouteDescriptions(IHttpRoute route, IReadOnlyCollection<ApiDescription> apiDescriptions)
    {
        if (route.DataTokens["actions"] is IEnumerable<HttpActionDescriptor> actionDescriptor &&
            actionDescriptor.Any())
            GetPopulateMethod().Invoke(_innerApiExplorer,
                new object[] {actionDescriptor.First(), route, route.RouteTemplate, apiDescriptions});
    }

    private MethodInfo GetPopulateMethod()
    {
        if (_apiDescriptionPopulator == null)
            _apiDescriptionPopulator = _innerApiExplorer.GetType()
                .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(
                    m => m.Name == "PopulateActionDescriptions" && m.GetParameters().Length == 4);

        return _apiDescriptionPopulator;
    }

    public static IEnumerable<IHttpRoute> FlattenRoutes(IEnumerable<IHttpRoute> routes)
    {
        foreach (var route in routes)
        {
            switch (route)
            {
                case HttpRoute _:
                    yield return route;
                    break;
                case IReadOnlyCollection<IHttpRoute> subRoutes:
                {
                    foreach (var subRoute in FlattenRoutes(subRoutes))
                        yield return subRoute;
                    break;
                }
            }
        }
    }
}