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, но код указан для иллюстративных целей.
Надеюсь, это поможет кому-то еще в будущем:) Удачи!