Swashbuckle 5 can't find my ApiControllers

2020-02-26 14:27发布

I'm at a point where I really need API documentation for my WebAPI 2 project, and I used the Swashbuckle 5 NuGet package. Out of the box, I can hit {myrooturl}/swagger and a UI pops up, but there are no controllers, methods, or anything in there. Just my title: [ base url: /EM.Services , api version: v1 ]

I took a look at the Swashbuckle docs, and since I'm using OWIN which is hosted by IIS, I modified the SwaggerConfig with:

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

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

I also setup the build of the project to generate the XML docs and pointed my SwaggerConfig to it with:

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

I'm not sure if the XML docs working/not-working has anything to do with it though, as I get absolutely no controllers on the swagger-ui page.

For what it's worth, all of my controller inherit from a BaseController, which in turn inherits from ApiController.

Is there something screwy with my 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"));
    }

My concrete controllers all look like this (I've tried subbing out BaseController for ApiController and there is no change):

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

and my Base controller doesn't do much (yet), just has an attribute:

[BuildClaims]
public abstract class BaseController : ApiController

The empty page persists across using IIS Express or full blown IIS.

Update: Example of a contrived controller I made that is really basic. It also does not show up, as I still have the boiler plate swagger ui with nothing in it.

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

8条回答
混吃等死
2楼-- · 2020-02-26 15:18

I found the problem. After creating an empty test project, I noticed that the WebApiConfiguration was being registered from the global.asax app start and not the OWIN startup class (like I did).

Since Swagger/Swashbuckle is hooking into the GlobalConfiguration and also given that OWIN startup and Global.asax live in different contexts (I think), the fix is to wire up your WebAPI stuff to register from Global.asax and to have OWIN's app object use WebAPI.

Relevant bits:

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

    }

After rewiring as above, I can now see controllers & actions in swagger UI.

查看更多
不美不萌又怎样
3楼-- · 2020-02-26 15:19

I found that I had the same issue. I created an extension method to help

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

Then in my 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);
    }
}
查看更多
登录 后发表回答