visual studio nswag net how asp c# iis asp.net-web-api swashbuckle

c# - studio - Swashbuckle 5 no puede encontrar mis ApiControllers



swagger visual studio 2017 (7)

Estoy en un punto en el que realmente necesito la documentación API para mi proyecto WebAPI 2, y utilicé el paquete Swashbuckle 5 NuGet. Al salir de la caja, puedo presionar {myrooturl} / swagger y aparece una IU, pero no hay controladores, métodos ni nada allí. Solo mi título: [base url: /EM.Services, api version: v1]

Eché un vistazo a los documentos de Swashbuckle, y como estoy utilizando OWIN hospedado por IIS, modifiqué SwaggerConfig con:

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

según este documento: https://github.com/domaindrivendev/Swashbuckle/blob/1326e753ce9b3a823b3c156b0b601134692ffc58/README.md#transitioning-to-swashbuckle-50

También configuré la construcción del proyecto para generar los documentos XML y señalé mi SwaggerConfig con:

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

Sin embargo, no estoy seguro si los documentos XML que funcionan / no funcionan tienen algo que ver con esto, ya que no tengo absolutamente ningún controlador en la página de swagger-ui.

Por lo que vale, todos mis controladores heredan de un BaseController, que a su vez hereda de ApiController.

¿Hay algún problema con mi 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")); }

Todos mis controladores concretos se ven así (he intentado sustituir BaseController por ApiController y no hay cambios):

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

y mi controlador Base no hace mucho (todavía), solo tiene un atributo:

[BuildClaims] public abstract class BaseController : ApiController

La página vacía persiste al usar IIS Express o IIS completo.

Actualización: Ejemplo de un controlador artificial que hice que es realmente básico. Tampoco aparece, ya que todavía tengo la placa de caldera swagger ui sin nada en ella.

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


Swashbuckle se encuentra en la parte superior de la capa de metadatos de ApiExplorer , ApiExplorer . Toma las descripciones de operación de ApiExplorer y luego las asigna a las descripciones de Swagger.

Como su controlador hereda de BASECONTROLLER y no de APICONTROLLER, no funcionará

Por el comentario de JimWolleys

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

este es el método que alimenta Swashbuckle para obtener todas las llamadas de API. Se necesita un IApiExplorer. Que si no se modificó para tomar algo diferente toma el ApiExplorer predeterminado provisto. Que solo tiene información sobre cosas que heredan de ApiController

Swashbuckle git repo. solo busque GetApiDescriptionsFor y lo llevará directo al método


Encontré el problema. Después de crear un proyecto de prueba vacío, noté que WebApiConfiguration se estaba registrando desde el inicio de la aplicación global.asax y no desde la clase de inicio de OWIN (como hice yo).

Como Swagger / Swashbuckle se conecta a GlobalConfiguration y dado que el inicio de OWIN y Global.asax viven en diferentes contextos (creo), la solución es conectar sus elementos de WebAPI para registrarse desde Global.asax y utilizar el objeto de la aplicación de OWIN. WebAPI.

Bits relevantes:

// 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); }

Después de volver a cablear como se muestra arriba, ahora puedo ver los controladores y las acciones en la interfaz de usuario de swagger.


Me quedé atrapado ... y estas respuestas no me ayudaron del todo ... aunque me llevaron allí. Solo para salvar a otras personas un tiempo:

Tienes que pasar la configuración HTTP de OWIN y luego registrarte en eso en lugar de usar la clase GlobalConfiguration de la siguiente manera:

//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); }

y en el archivo de configuración swagger, cambie el método de registro a:

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

Espero que esto ayude.


Encontré este enlace muy útil. Esta solución en particular es específica de una API de Microsoft.Azure.Mobile.Server, pero me solucionó el problema.

Azure Mobile Apps Server y Swagger


Descubrí que tenía el mismo problema. Creé un método de extensión para ayudar

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; } }

Luego en mi 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); } }


Todas estas soluciones funcionan para mí, pero todas son solo trucos desagradables para mi problema. Después de unas horas de investigación descubrí que el problema es que también uso Glimpse (u otros paquetes que cambian la tabla de rutas).

Aquí hay un gran resumen: https://github.com/domaindrivendev/Swashbuckle/issues/468#issuecomment-139246748

  1. Glimpse agrega proxies de castillo sobre HttpWebRoute. Así que HostedHttpRouteCollection es una colección de RouteProxy y no de HttpWebRoute .
  2. La clase APIExplorer tiene el método FlattenRoutes que hace un bucle foreach sobre HostedHttpRouteCollection.
  3. La implementación de GetEnumerator de HostedHttpRouteCollection busca específicamente HttpWebRoute. Vea el código a continuación. Como el visor tiene proxies adicionales, el enumerador siempre devuelve 0 rutas.

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

Tengo miedo de que no haya solución, puede elegir lo que quiere usar: Swashbuckle o Glimpse , pero no ambos juntos .

Por supuesto, puede intentar ejecutar una de estas soluciones, pero existe el riesgo de un comportamiento inesperado y errores complicados.


Simplemente tuve el mismo problema y ninguno de estos me ayudó.

Después de perder el tiempo, me di cuenta de que las rutas que había etiquetado como [System.Web.Mvc.Route("visit")] no estaban siendo descubiertas por swagger.

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

pero [System.Web.Http.Route("visit")] es

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

No estoy 100% seguro, pero si importa, también cambié de

public class MyAPIController : Controller

a:

public class MyAPIController : System.Web.Http.ApiController

Más exactamente eliminé la declaración "using" para System.Web.Mvc, pero el código se enumera con fines ilustrativos.

Espero que esto ayude a alguien más en el futuro :) ¡Buena suerte!