Swashbuckle 5 не может найти мой ApiControllers

Я нахожусь в точке, где мне действительно нужна документация API для моего проекта WebAPI 2, и я использовал пакет Swashbuckle 5 NuGet. Из коробки я могу ударить {myrooturl}/swagger, и пользовательский интерфейс появляется, но нет контроллеров, методов или чего-то еще. Просто мой заголовок: [base url:/EM.Services, api version: v1]

Я просмотрел документы Swashbuckle, и поскольку я использую OWIN, который размещен в IIS, я модифицировал SwaggerConfig с помощью

c.RootUrl(req => req.RequestUri.GetLeftPart(UriPartial.Authority) + req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));

в соответствии с этим документом: https://github.com/domaindrivendev/Swashbuckle/blob/1326e753ce9b3a823b3c156b0b601134692ffc58/README.md#transitioning-to-swashbuckle-50

Я также настраиваю сборку проекта для создания документов XML и указывал на свой SwaggerConfig:

    private static string GetXmlCommentsPath()
    {
        // tried with an without the \bin
        return String.Format(@"{0}\bin\EM.Services.XML", AppDomain.CurrentDomain.BaseDirectory);
    }

Я не уверен, что рабочие документы XML не работают с ним, хотя я не получаю абсолютно никаких контроллеров на странице swagger-ui.

Для чего это стоит, весь мой контроллер наследует от BaseController, который, в свою очередь, наследуется от ApiController.

Есть ли что-то с моим WebApiConfig?

    public static void Register(HttpConfiguration config)
    {

        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        config.Filters.Add(new ValidateModelAttribute());

        config.Filters.Add(new BaseAuthenticationAttribute());

        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
    }

Мои конкретные контроллеры выглядят так (я попытался подстроить BaseController для ApiController и нет никаких изменений):

[RoutePrefix("api/whatever")]
public class FooController : BaseController

и мой базовый контроллер не делает много (пока), просто имеет атрибут:

[BuildClaims]
public abstract class BaseController : ApiController

Пустая страница сохраняется с использованием IIS Express или полномасштабного IIS.

Обновление: Пример надуманного контроллера, который я сделал, действительно является основным. Он также не появляется, так как у меня все еще есть кусочек плиты утиля без ничего.

/// <summary>
/// I am a test
/// </summary>
[RoutePrefix("api/dummy")]
public class DummyController : ApiController
{
    [HttpGet]
    [Route("foo")]
    public int Foo()
    {
        return 42;
    }
}

Ответы

Ответ 1

Я нашел проблему. После создания пустого тестового проекта я заметил, что WebApiConfiguration регистрировался из начала приложения global.asax, а не класса запуска OWIN (как и я).

Так как Swagger/Swashbuckle подключается к GlobalConfiguration, а также при условии, что запуск OWIN и Global.asax живут в разных контекстах (я думаю), исправление заключается в подключении вашего материала WebAPI для регистрации из Global.asax и наличия OWIN приложение использует WebAPI.

Соответствующие биты:

   // global asax
    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
       // ... more stuff
    }

   //startup.cs
   public void Configuration(IAppBuilder app)
    {
        // This must happen FIRST otherwise CORS will not work.
        app.UseCors(CorsOptions.AllowAll);

        HttpConfiguration config = new HttpConfiguration();

        ConfigureAuth(app);

        // webapi is registered in the global.asax
        app.UseWebApi(config);

    }

После перезаписи, как указано выше, теперь я могу видеть контроллеры и действия в пользовательском интерфейсе swagger.

Ответ 2

Я застрял.. и эти ответы не помогли мне полностью... хотя они и привели меня туда. Просто чтобы спасти других людей некоторое время:

Вам нужно передать http config из OWIN, а затем зарегистрировать его вместо использования класса GlobalConfiguration следующим образом:

//starup.cs
public void Configuration(IAppBuilder app)
    {
        Config = new HttpConfiguration();
        WebApiConfig.Register(Config);

        app
            .UseResponseLogging()
            .UseRequestLogging()
            .UseHttpErrors()
            .UseExceptionLogging()
            .UseWebApi(Config);

        HandlerConfig.Register(Config);

        SwaggerConfig.Register(Config);
    }

и в конфигурационном файле swagger измените метод register на:

public static void Register(HttpConfiguration config)
    {
        var thisAssembly = typeof(SwaggerConfig).Assembly;

        config
            .EnableSwagger(c =>
                {...

Надеюсь, что это поможет.

Ответ 3

Все эти решения работают для меня, но все они просто неприятные хаки для моей проблемы. После нескольких часов расследования выяснилось, что проблема в том, что я также использую Glimpse (или другие пакеты, которые изменяют таблицу маршрутов).

Вот отличная сводка: https://github.com/domaindrivendev/Swashbuckle/issues/468#issuecomment-139246748

  • Glimpse добавляет прокси-серверы на вершине HttpWebRoute. Таким образом HostedHttpRouteCollection представляет собой коллекцию RouteProxy, а не HttpWebRoute.
  • Класс APIExplorer имеет метод FlattenRoutes, который выполняет цикл foreach через HostedHttpRouteCollection.
  • GetEnumerator реализация HostedHttpRouteCollection специально ищет HttpWebRoute. См. Код ниже. Поскольку проблеск добавили прокси, перечислитель всегда возвращает 0 маршрутов!!

    public override IEnumerator GetEnumerator()
    {
         // Here we only care about Web API routes.
         return _routeCollection
             .OfType()
             .Select(httpWebRoute => httpWebRoute.HttpRoute)
             .GetEnumerator();
    }

Я боюсь, что нет решения, вы можете выбрать то, что вы хотите использовать: Swashbuckle или Glimpse, но не оба вместе.

Конечно, вы можете попробовать запустить один из этих обходных решений, но есть риск неожиданного поведения и сложных ошибок.

Ответ 4

Я обнаружил, что у меня такая же проблема. Я создал метод расширения, чтобы помочь

using Swashbuckle.Application;
using System.Web.Http;

public static class SwaggerExtensions
{
    public static HttpConfiguration EnableSwagger(this HttpConfiguration httpConfiguration)
    {
        httpConfiguration
            .EnableSwagger(c => c.SingleApiVersion("v1", "A title for your API"))
            .EnableSwaggerUi();
        return httpConfiguration;
    }
}

Затем в моем Startup.cs

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        HttpConfiguration httpConfiguration = new HttpConfiguration();

        httpConfiguration
            .EnableSwagger()    // <==== EXTENSION METHOD <==== //
            .MapHttpAttributeRoutes();

        httpConfiguration.Routes.MapHttpRoute(
            "DefaultApi",
            "api/{controller}/{id}",
            new {id = RouteParameter.Optional});

        appBuilder
            .UseWebApi(httpConfiguration);
    }
}

Ответ 5

Swashbuckle располагается поверх слоя метаданных WebApi ApiExplorer. Он берет описания операций из ApiExplorer и затем сопоставляет их описаниям Swagger.

Поскольку ваш контроллер наследует от BASECONTROLLER, а не APICONTROLLER, он не будет работать

Комментарий от пользователя JimWolleys

 private IEnumerable<ApiDescription> GetApiDescriptionsFor(string apiVersion)
    {
        return (_options.VersionSupportResolver == null)
            ? _apiExplorer.ApiDescriptions
            : _apiExplorer.ApiDescriptions.Where(apiDesc => _options.VersionSupportResolver(apiDesc, apiVersion));
    }

это метод, который заставляет Swashbuckle получать все вызовы api. Требуется IApiExplorer. Который, если он не был изменен, чтобы принять что-то другое, он принимает предоставленный по умолчанию ApiExplorer. У которого есть только информация о вещах, которые наследуются от ApiController

Swashbuckle git repo. просто найдите GetApiDescriptionsFor, и он перенесет вас прямо к методу

Ответ 6

Я нашел эту ссылку очень полезной. Это конкретное решение специфично для Microsoft.Azure.Mobile.Server API, но оно решило проблему для меня.

Azure Mobile Apps Server и Swagger

Ответ 7

У меня была одна и та же проблема, и ни одна из них не помогла мне.

После некоторого беспорядка я понял, что маршруты, которые я назвал [System.Web.Mvc.Route("visit")], не были обнаружены с помощью swagger.

    [HttpGet]
    // ROUTE ATTRIBUTE NOT FOUND BY SWAGGER
    [System.Web.Mvc.Route("visit")]
    public string Visit()
    {

но [System.Web.Http.Route("visit")] есть

    [HttpGet]
    // ROUTE ATTRIBUTE *IS* FOUND BY SWAGGER
    [System.Web.Http.Route("visit")]
    public string Visit()
    {

Я не уверен на 100%, но если это имеет значение, я также переключился с

 public class MyAPIController : Controller

в

 public class MyAPIController : System.Web.Http.ApiController

Более точно я удалил инструкцию "using" для System.Web.Mvc, но код указан для иллюстративных целей.

Надеюсь, это поможет кому-то еще в будущем:) Удачи!