我有两个方法的Web API控制器 - 假设第一个方法返回普通项目列表,第二个方法返回分配给特定用户的所有项目。
public class ProjectController: ApiController
{
public IQueryable<Project> Get() { ... }
[HttpGet]
public IQueryable<Project> ForUser(int userId) { ... }
}
在这种情况下,方法实现并不重要。
还调整了Web API路由配置以支持自定义方法名称。
config.Routes.MapHttpRoute(
"DefaultApi",
"api/v1/{controller}/{id}",
new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
"DefaultApiWithAction",
"api/v1/{controller}/{action}");
它运行正常,我可以访问/api/v1/projects/
和/api/v1/projects/forUser/
个端点,但似乎路由引擎太聪明了,所以它决定/api/v1/projects?userId=1
请求可能与{{1}匹配}}方法(由于ForUser(..)
参数名称,我猜)并忽略路由的userId
部分。
有没有办法避免这种行为,并要求在URL中明确指定操作部分?
答案 0 :(得分:3)
夫妻俩。首先是这条路线:
config.Routes.MapHttpRoute(
"DefaultApiWithAction",
"api/v1/{controller}/{action}",
new { id = RouteParameter.Optional });
没有“action”作为可选参数。您已将id
作为可选项(我假设为拼写错误),但由于路径中不存在,因此您不会仅与一个辅助段匹配。只有包含两个部分(控制器和操作)的URL才会通过此路由。这个网址:
/api/v1/projects?userId=1
...包含单个细分,但不包含。此路由以及缺少第二个组件的任何其他路由将默认为此路由:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
...只接受控制器和可选ID。您需要重新格式化给定的URL以获取操作参数,或重写路由以使操作可选,并根据需要设置默认值。这将取决于您的应用程序架构,但总是在简单性方面犯错误。路线可能变得非常复杂 - 通常更简单。
对于必需/可选路线组件,请记住以下两点:
placeholder = value
形式的匿名对象中提供默认值来设置。答案 1 :(得分:0)
我完全不明白你的问题。
不应该/api/v1/projects?userId=1
确实调用ForUser操作吗?
无论如何,要做出必要的动作,请按照以下方式制作你的HttpRoute:
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional });
现在你可以像这样打电话:
/api/v1/projects/ForUser/2
答案 2 :(得分:0)
我终于找到了满足我要求的解决方案。我已将 levib 和 user1797792 建议的this answer和想法合并到以下配置中:
config.Routes.MapHttpRoute(
"DefaultApiWithActionAndOptionalId",
"api/v1/{controller}/{action}/{id}",
new {id = RouteParameter.Optional});
config.Routes.MapHttpRoute(
"DefaultApiGet",
"api/v1/{controller}",
new { action = "Get" },
new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
请注意,配置顺序非常重要。
首先,带有任何查询字符串的/api/v1/projects
请求(即使参数名称与其他操作的参数匹配)也会通过第二个调度发送到Get()
方法路线。这很重要,因为在实际项目中,我有一个附加到此操作的自定义操作过滤器,它根据提供的请求参数过滤返回的IQueryable
。
api/v1/projects/forUser/1
- 类似请求将通过第一条路由发送到ForUser(int id)
方法。将userId
参数重命名为id
,可以构建更清晰的网址。
显然,这种方法有一些局限性,但在我的具体情况下,这就是我所需要的。