问题描述
在使用的ASP.NET Web API帮助页和相关的 MVC.ApiExplorer 我拥有有效的途径是通过HTTP访问还没有被发现ApiExplorer。当使用一般的路由规则,这些路由才发现。更具体的规则(与一般的结合)的用法似乎隐藏在ApiExplorer路线。
When using ASP.NET Web API Help Page and the related MVC.ApiExplorer I have valid routes that are accessible via http yet aren't discovered by ApiExplorer. These routes are only found when a general routing rule is used. Usage of a more specific rule (in conjunction with the general one) seems to hide routes from the ApiExplorer.
在三个规则时的例子两条航线涉及到一个GET和上采取任何的查询参数的控制方法的POST操作去MIA。
In an example case of three rules two routes relate to a GET and a POST action on a controller method which take no query parameters go MIA.
public class SomeControllerController : ApiController
{
[HttpPost] public HttpResponseMessage Post(PostObject value) { ... }
[HttpGet] public IEnumerable<DisplayObject> GetAll() { ... }
[HttpGet] public DisplayObject GetById(string id) { ... }
}
在使用的路由规则
routes.MapHttpRoute(
name: "ApiDefault",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
}
);
的路由是按照API浏览器适当发现的
The routes are discovered appropriately by Api Explorer as
- POST:API / SomeController
- GET:API / SomeController
- GET:API / SomeController / {ID}
还加入比较特殊的,更有意义的规则时
yet when adding the less generic and more meaningful rule
routes.MapHttpRoute(
name: "ApiSomeControllerDefault",
routeTemplate: "api/somecontroller/{id}",
defaults: new
{
controller = "SomeController",
id = RouteParameter.Optional
}
);
routes.MapHttpRoute(
name: "ApiDefault",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
}
);
API浏览器只返回
- GET:API / somecontroller / {ID}
什么引起我的一些路线不被发现?
What is causing some of my routes not to be found?
修改
Link发布关于ApiExplorer项目页面报告
推荐答案
虽然这个错误不是由的ASP.NET Web API团队固定的,我用我自己的愚蠢补丁。
While this bug is not fixed by ASP.NET Web API team, I'm using my own dumb fix.
我对 IApiExplorer
扩展方法在做同样的事情,原来的 ApiDescriptions
实施但ApiExplorer
类,而不是删除了不同的路线重复的动作,它只是返回不同的ID(HTTP方法+路由)的行动。因此,它返回所有宣布的行动,无论是路线计算。
My extension method for IApiExplorer
is doing the same things as original ApiDescriptions
implementation in ApiExplorer
class, but instead of removing duplicate actions for different routes, it just returns actions with distinct ID (HTTP method + route). So it returns all declared actions, regardless of the routes count.
和,是的,它无耻地使用反射来调用私有方法。
And, yes, it shamelessly uses reflection to call the private method.
public static class WebApiExtensions
{
public static Collection<ApiDescription> GetAllApiDescriptions(this IApiExplorer apiExplorer, HttpConfiguration httpConfig)
{
if (!(apiExplorer is ApiExplorer))
{
return apiExplorer.ApiDescriptions;
}
IList<ApiDescription> apiDescriptions = new Collection<ApiDescription>();
var controllerSelector = httpConfig.Services.GetHttpControllerSelector();
var controllerMappings = controllerSelector.GetControllerMapping();
if (controllerMappings != null)
{
foreach (var route in httpConfig.Routes)
{
typeof(ApiExplorer).GetMethod("ExploreRouteControllers",
bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
binder: null,
types: new[] {typeof(IDictionary<string, HttpControllerDescriptor>), typeof(IHttpRoute), typeof(Collection<ApiDescription>)},
modifiers: null
).Invoke(apiExplorer, new object[] {controllerMappings, route, apiDescriptions});
}
apiDescriptions = apiDescriptions
.GroupBy(api => api.ID.ToLower())
.Select(g => g.First())
.ToList();
}
return new Collection<ApiDescription>(apiDescriptions);
}
}
这很容易使用:
var apiDescriptions = apiExplorer.GetAllApiDescriptions(httpConfig);
HttpConfiguration
参数添加了可测试性。如果你不关心它,除去该参数,只需要使用 GlobalConfiguration.HttpConfiguration
直接扩展方法。
HttpConfiguration
parameter added for testability. If you don't care about it, remove the parameter and just use GlobalConfiguration.HttpConfiguration
in the extension method directly.
这篇关于有效的路由不MVC.ApiExplorer发现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!