Swashbuckle 5 找不到我的 ApiControllers
Swashbuckle 5 can't find my ApiControllers
我确实需要 API WebAPI 2 项目的文档,并且我使用了 Swashbuckle 5 NuGet 包。开箱即用,我可以点击 {myrooturl}/swagger 并弹出 UI,但其中没有控制器、方法或任何东西。只是我的标题:[ base url: /EM.Services , api version: v1 ]
我查看了 Swashbuckle 文档,由于我使用的是 IIS 托管的 OWIN,因此我修改了 SwaggerConfig:
c.RootUrl(req => req.RequestUri.GetLeftPart(UriPartial.Authority) + req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));
我还设置了项目的 build 以生成 XML 文档并将我的 SwaggerConfig 指向它:
private static string GetXmlCommentsPath()
{
// tried with an without the \bin
return String.Format(@"{0}\bin\EM.Services.XML", AppDomain.CurrentDomain.BaseDirectory);
}
我不确定 XML 文档 working/not-working 是否与它有任何关系,因为我在 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
我的 Base 控制器(目前)还没有做太多事情,只有一个属性:
[BuildClaims]
public abstract class BaseController : ApiController
使用 IIS Express 或完整的 IIS 时,空白页面仍然存在。
更新:
我制作的一个非常基本的人为控制器示例。它也没有出现,因为我仍然有样板招摇 ui,里面什么也没有。
/// <summary>
/// I am a test
/// </summary>
[RoutePrefix("api/dummy")]
public class DummyController : ApiController
{
[HttpGet]
[Route("foo")]
public int Foo()
{
return 42;
}
}
Swashbuckle 位于 WebApi 的元数据层之上 ApiExplorer
。它从 ApiExplorer 获取操作描述,然后将它们映射到 Swagger 描述。
由于您的控制器继承自 BASECONTROLLER 而不是 APICONTROLLER,因此它将无法工作
根据 JimWolley 的评论
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
继承的东西的信息
我发现了问题。创建一个空的测试项目后,我注意到 WebApiConfiguration 是从 global.asax 应用程序启动而不是 OWIN 启动 class(就像我所做的那样)注册的。
由于 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 中的控制器和动作 UI。
我卡住了……这些答案并没有完全帮助我……尽管他们把我带到了那里。只是为了节省其他人一些时间:
您必须从 OWIN 传递 http 配置,然后在上面注册,而不是像这样使用 GlobalConfiguration class:
//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配置文件中,将注册方法更改为:
public static void Register(HttpConfiguration config)
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
config
.EnableSwagger(c =>
{...
希望对您有所帮助。
我发现这个 link 非常有帮助。这个特定的解决方案特定于 Microsoft.Azure.Mobile.Server API 但它解决了我的问题。
我发现我遇到了同样的问题。我创建了一个扩展方法来帮助
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);
}
}
所有这些解决方案都适用于我,但它们都只是针对我的问题的讨厌的黑客攻击。经过几个小时的调查,我发现问题是我还使用了 Glimpse(或其他更改路由 table 的包)。
这里有一个很好的总结:https://github.com/domaindrivendev/Swashbuckle/issues/468#issuecomment-139246748
- Glimpse adds castle proxies on top of HttpWebRoute. So HostedHttpRouteCollection is collection of RouteProxy and not
HttpWebRoute.
- APIExplorer class has FlattenRoutes method which does a foreach loop over HostedHttpRouteCollection.
GetEnumerator implementation of HostedHttpRouteCollection specifically look for HttpWebRoute. See the code below. Since glimpse
has added proxies, enumerator always returns 0 routes!!
public override IEnumerator GetEnumerator()
{
// Here we only care about Web API routes.
return _routeCollection
.OfType()
.Select(httpWebRoute => httpWebRoute.HttpRoute)
.GetEnumerator();
}
恐怕没有解决办法,你可以选择你想用的:Swashbuckle或Glimpse,但是不是两个都在一起。
当然,您可以尝试 运行 这些解决方法之一,但存在意外行为和棘手错误的风险。
我自己也遇到了同样的问题,none 帮助了我。
经过一番摸索后,我发现我标记为 [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
更准确地说,我删除了 System.Web.Mvc 的 "using" 语句,但列出代码是为了说明目的。
希望这对以后的其他人有帮助 :) 祝你好运!
我在 Owin + Swashbuckle 集成方面遇到了很多问题,none 这些答案为我解决了所有问题。长话短说,我设法解决了所有问题并创建了一个开源存储库,用作任何需要它的人的模板。
我在使用 OWIN 时也遇到了这个问题。通过按照 here 中的建议仅安装 Swashbuckler Core 并按如下方式编辑 Startup.cs 来解决此问题:
// Startup.cs
// ...
HttpConfiguration config = new HttpConfiguration();
// ...
config
.EnableSwagger(c =>
{
////add if there's custom root path
//c.RootUrl(req =>
// req.RequestUri.GetLeftPart(UriPartial.Authority) +
// req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));
c.SingleApiVersion("v1", "A title for your API");
})
.EnableSwaggerUi();
// ...
appBuilder.UseWebApi(config);
我熟悉 Swashbuckle 的 .NET 核心版本,它可以自动扩展控制器。当我在做一个框架(非核心)时API,当我终于设法展示一些东西时,我很困惑,因为我不知道点击show/hide并且仍然认为它不是正在工作。
您可以使用以下内容默认展开它:
.EnableSwaggerUi(c => {
c.DocExpansion(DocExpansion.List);
});
就我而言,我遇到了与 Alex C 类似的问题。我必须做两件事来解决它:
第一件事是我有一个关于使用 MVC 的导入声明,像这样:
using System.Web.Mvc;
我删除了那个 import 语句,这解决了一半的问题。我注意到的另一件事是,在 Swashbucke 中出现的 是 的控制器之一有这样的注释
[RoutePrefix("v1/Awesome")]
其中Awesome
是控制器AwesomeController的名字。所以我把那个路由前缀注释放在我的 class 声明之前,现在它出现在 Swagger 界面中
[RoutePrefix("v1/Amazing")]
public class AmazingController : ApiController
因此,如果其他人遇到此问题,您可以检查是否需要像我一样添加路由前缀。
我确实需要 API WebAPI 2 项目的文档,并且我使用了 Swashbuckle 5 NuGet 包。开箱即用,我可以点击 {myrooturl}/swagger 并弹出 UI,但其中没有控制器、方法或任何东西。只是我的标题:[ base url: /EM.Services , api version: v1 ]
我查看了 Swashbuckle 文档,由于我使用的是 IIS 托管的 OWIN,因此我修改了 SwaggerConfig:
c.RootUrl(req => req.RequestUri.GetLeftPart(UriPartial.Authority) + req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));
我还设置了项目的 build 以生成 XML 文档并将我的 SwaggerConfig 指向它:
private static string GetXmlCommentsPath()
{
// tried with an without the \bin
return String.Format(@"{0}\bin\EM.Services.XML", AppDomain.CurrentDomain.BaseDirectory);
}
我不确定 XML 文档 working/not-working 是否与它有任何关系,因为我在 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
我的 Base 控制器(目前)还没有做太多事情,只有一个属性:
[BuildClaims]
public abstract class BaseController : ApiController
使用 IIS Express 或完整的 IIS 时,空白页面仍然存在。
更新: 我制作的一个非常基本的人为控制器示例。它也没有出现,因为我仍然有样板招摇 ui,里面什么也没有。
/// <summary>
/// I am a test
/// </summary>
[RoutePrefix("api/dummy")]
public class DummyController : ApiController
{
[HttpGet]
[Route("foo")]
public int Foo()
{
return 42;
}
}
Swashbuckle 位于 WebApi 的元数据层之上 ApiExplorer
。它从 ApiExplorer 获取操作描述,然后将它们映射到 Swagger 描述。
由于您的控制器继承自 BASECONTROLLER 而不是 APICONTROLLER,因此它将无法工作
根据 JimWolley 的评论
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
继承的东西的信息我发现了问题。创建一个空的测试项目后,我注意到 WebApiConfiguration 是从 global.asax 应用程序启动而不是 OWIN 启动 class(就像我所做的那样)注册的。
由于 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 中的控制器和动作 UI。
我卡住了……这些答案并没有完全帮助我……尽管他们把我带到了那里。只是为了节省其他人一些时间:
您必须从 OWIN 传递 http 配置,然后在上面注册,而不是像这样使用 GlobalConfiguration class:
//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配置文件中,将注册方法更改为:
public static void Register(HttpConfiguration config)
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
config
.EnableSwagger(c =>
{...
希望对您有所帮助。
我发现这个 link 非常有帮助。这个特定的解决方案特定于 Microsoft.Azure.Mobile.Server API 但它解决了我的问题。
我发现我遇到了同样的问题。我创建了一个扩展方法来帮助
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);
}
}
所有这些解决方案都适用于我,但它们都只是针对我的问题的讨厌的黑客攻击。经过几个小时的调查,我发现问题是我还使用了 Glimpse(或其他更改路由 table 的包)。
这里有一个很好的总结:https://github.com/domaindrivendev/Swashbuckle/issues/468#issuecomment-139246748
- Glimpse adds castle proxies on top of HttpWebRoute. So HostedHttpRouteCollection is collection of RouteProxy and not HttpWebRoute.
- APIExplorer class has FlattenRoutes method which does a foreach loop over HostedHttpRouteCollection.
GetEnumerator implementation of HostedHttpRouteCollection specifically look for HttpWebRoute. See the code below. Since glimpse has added proxies, enumerator always returns 0 routes!!
public override IEnumerator GetEnumerator() { // Here we only care about Web API routes. return _routeCollection .OfType() .Select(httpWebRoute => httpWebRoute.HttpRoute) .GetEnumerator(); }
恐怕没有解决办法,你可以选择你想用的:Swashbuckle或Glimpse,但是不是两个都在一起。
当然,您可以尝试 运行 这些解决方法之一,但存在意外行为和棘手错误的风险。
我自己也遇到了同样的问题,none 帮助了我。
经过一番摸索后,我发现我标记为 [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
更准确地说,我删除了 System.Web.Mvc 的 "using" 语句,但列出代码是为了说明目的。
希望这对以后的其他人有帮助 :) 祝你好运!
我在 Owin + Swashbuckle 集成方面遇到了很多问题,none 这些答案为我解决了所有问题。长话短说,我设法解决了所有问题并创建了一个开源存储库,用作任何需要它的人的模板。
我在使用 OWIN 时也遇到了这个问题。通过按照 here 中的建议仅安装 Swashbuckler Core 并按如下方式编辑 Startup.cs 来解决此问题:
// Startup.cs
// ...
HttpConfiguration config = new HttpConfiguration();
// ...
config
.EnableSwagger(c =>
{
////add if there's custom root path
//c.RootUrl(req =>
// req.RequestUri.GetLeftPart(UriPartial.Authority) +
// req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));
c.SingleApiVersion("v1", "A title for your API");
})
.EnableSwaggerUi();
// ...
appBuilder.UseWebApi(config);
我熟悉 Swashbuckle 的 .NET 核心版本,它可以自动扩展控制器。当我在做一个框架(非核心)时API,当我终于设法展示一些东西时,我很困惑,因为我不知道点击show/hide并且仍然认为它不是正在工作。
您可以使用以下内容默认展开它:
.EnableSwaggerUi(c => {
c.DocExpansion(DocExpansion.List);
});
就我而言,我遇到了与 Alex C 类似的问题。我必须做两件事来解决它:
第一件事是我有一个关于使用 MVC 的导入声明,像这样:
using System.Web.Mvc;
我删除了那个 import 语句,这解决了一半的问题。我注意到的另一件事是,在 Swashbucke 中出现的 是 的控制器之一有这样的注释
[RoutePrefix("v1/Awesome")]
其中Awesome
是控制器AwesomeController的名字。所以我把那个路由前缀注释放在我的 class 声明之前,现在它出现在 Swagger 界面中
[RoutePrefix("v1/Amazing")]
public class AmazingController : ApiController
因此,如果其他人遇到此问题,您可以检查是否需要像我一样添加路由前缀。