web-dev-qa-db-fra.com

Swashbuckle 5 ne trouve pas mes ApiControllers

Je suis à un point où j'ai vraiment besoin de la documentation API pour mon projet WebAPI 2 et j'ai utilisé le package Swashbuckle 5 NuGet. Hors de la boîte, je peux frapper {myrooturl}/swagger et une interface utilisateur apparaît, mais il n'y a aucun contrôleur, méthode ou quoi que ce soit à l'intérieur. Juste mon titre: [base url: /EM.Services, version d'api: v1]

J'ai jeté un coup d'œil aux documents Swashbuckle et, comme j'utilise OWIN, hébergé par IIS, j'ai modifié SwaggerConfig avec:

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

selon cette doc: https://github.com/domaindrivendev/Swashbuckle/blob/1326e753ce9b3a823b3c156b0b601134692ffc58/README.md#transitioning-to-swashbuckle-50

J'ai également configuré la construction du projet pour générer les documents XML et j'ai pointé mon SwaggerConfig avec:

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

Je ne suis pas sûr que la documentation XML qui fonctionne/ne fonctionne pas y soit pour quelque chose, cependant, car je n'ai absolument aucun contrôleur sur la page swagger-ui.

Pour ce que cela vaut, tous mes contrôleurs héritent d'un BaseController, qui à son tour hérite d'ApiController.

Y at-il quelque chose de vicieux avec mon 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"));
    }

Mes contrôleurs concrets ressemblent tous à ceci (j'ai essayé de remplacer BaseController pour ApiController et il n'y a pas de changement):

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

et mon contrôleur de base ne fait pas (encore) beaucoup, a juste un attribut:

[BuildClaims]
public abstract class BaseController : ApiController

La page vide persiste avec IIS Express ou IIS complet.

Mise à jour: Exemple de contrôleur artificiel que j'ai fabriqué et qui est vraiment basique. Il n'apparaît pas non plus, car j'ai toujours la plaque de la chaudière qui ne contient rien.

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

J'ai trouvé le problème. Après avoir créé un projet de test vide, j'ai remarqué que WebApiConfiguration était en cours d'enregistrement à partir du démarrage de l'application global.asax et non de la classe de démarrage OWIN (comme je l'ai fait).

Puisque Swagger/Swashbuckle est connecté à GlobalConfiguration et compte tenu du fait que la startup OWIN et Global.asax vivent dans des contextes différents (je pense), le correctif consiste à câbler vos éléments WebAPI pour s'enregistrer à partir de Global.asax et pour permettre l'utilisation de l'objet d'application OWIN WebAPI.

Bits pertinents:

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

    }

Après avoir recâblé comme ci-dessus, je peux maintenant voir les contrôleurs et les actions dans l'interface utilisateur swagger.

21
Bill Sambrone

Je me suis retrouvé coincé… et ces réponses ne m'ont pas complètement aidée… bien qu'elles m'aient conduit là-bas. Juste pour gagner du temps à d’autres personnes:

Vous devez passer la configuration http à partir de OWIN, puis vous y inscrire au lieu d'utiliser la classe GlobalConfiguration comme suit

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

et dans le fichier de configuration swagger, modifiez la méthode de registre en:

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

        config
            .EnableSwagger(c =>
                {...

J'espère que cela t'aides.

17
Sumit Maingi

J'ai trouvé que j'avais le même problème. J'ai créé une méthode d'extension pour aider

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

Puis dans mon 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);
    }
}
3
chris31389

Toutes ces solutions fonctionnent pour moi, mais toutes ne sont que de vilains stratagèmes pour mon problème. Après quelques heures d’enquête, j’ai découvert que le problème c’est que j’utilise aussi Glimpse (ou d’autres paquetages qui changent de table d’acheminement).

Voici un excellent résumé: https://github.com/domaindrivendev/Swashbuckle/issues/468#issuecomment-139246748

  1. Glimpse ajoute des procurations de château au-dessus de HttpWebRoute. Alors HostedHttpRouteCollection est une collection de RouteProxy et non HttpWebRoute.
  2. La classe APIExplorer a la méthode FlattenRoutes qui effectue une boucle foreach sur HostedHttpRouteCollection.
  3. GetEnumerator implémentation de HostedHttpRouteCollection recherche spécifiquement HttpWebRoute. Voir le code ci-dessous. Depuis aperçu a ajouté des procurations, l'énumérateur renvoie toujours 0 routes !!

    remplacement public IEnumerator GetEnumerator () 
     {
     // Nous ne nous intéressons ici qu'aux routes de l'API Web .
     retourne _routeCollection 
     .OfType () 
     .Sélectionnez (httpWebRoute => httpWebRoute.HttpRoute) 
     .GetEnumerator (); 
    }

Je crains qu'il n'y ait pas de solution, vous pouvez choisir ce que vous voulez utiliser: Swashbuckle ou Glimpse, mais pas les deux ensemble.

Bien sûr, vous pouvez essayer d’appliquer une de ces solutions de contournement, mais il existe un risque de comportement inattendu et de bogues compliqués.

3
Marek Dorda

Je viens d'avoir le même problème moi-même et aucun de ceux-ci ne m'a aidé.

Après quelques discussions, j'ai compris que les routes que j'avais étiquetées comme étant [System.Web.Mvc.Route("visit")] n'étaient pas découvertes par swagger.

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

mais [System.Web.Http.Route("visit")] est

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

Je ne suis pas sûr à 100%, mais si c'est important, je suis aussi passé de

 public class MyAPIController : Controller

à:

 public class MyAPIController : System.Web.Http.ApiController

Plus précisément, j'ai supprimé l'instruction "using" pour System.Web.Mvc, mais le code est répertorié à des fins d'illustration.

J'espère que cela aidera quelqu'un d'autre à l'avenir :) Bonne chance!

1
Alex C

J'ai trouvé ce lien très utile. Cette solution particulière est spécifique à une API Microsoft.Azure.Mobile.Server mais elle a résolu le problème pour moi.

Serveur d'applications et Swagger Azure Mobile

0
Rod Hartzell

Swashbuckle se trouve au-dessus de la couche de métadonnées de WebApi ApiExplorer. Il prend les descriptions d'opération fournies par ApiExplorer, puis les mappe avec les descriptions Swagger.

Puisque votre contrôleur hérite de BASECONTROLLER et non d’APICONTROLLER, cela ne fonctionnera pas.

Par commentaire JimWolleys

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

c'est la méthode qui permet à Swashbuckle de recevoir tous les appels de l'API. Il faut un IApiExplorer. Lequel, s'il n'a pas été modifié pour prendre quelque chose de différent, prend le ApiExplorer fourni par défaut. Qui n'a que des informations sur des choses héritées d'ApiController

Swashbuckle git repo. il suffit de chercher GetApiDescriptionsFor et cela vous mènera directement à la méthode

0
gh9