C# 防止ASP.NET Web API路由引擎扣除自定义方法名称
我的Web API控制器有两个方法——假设第一个方法返回普通项目列表,第二个方法返回分配给特定用户的所有项目C# 防止ASP.NET Web API路由引擎扣除自定义方法名称,c#,asp.net-mvc,asp.net-web-api,C#,Asp.net Mvc,Asp.net Web Api,我的Web API控制器有两个方法——假设第一个方法返回普通项目列表,第二个方法返回分配给特定用户的所有项目 public class ProjectController: ApiController { public IQueryable<Project> Get() { ... } [HttpGet] public IQueryable<Project> ForUser(int userId) { ... } } 它工作得很好,我可以访问/
public class ProjectController: ApiController
{
public IQueryable<Project> Get() { ... }
[HttpGet]
public IQueryable<Project> ForUser(int userId) { ... }
}
它工作得很好,我可以访问/api/v1/projects/
和/api/v1/projects/forUser/
端点,但似乎路由引擎太聪明了,所以它决定/api/v1/projects?userId=1
请求可能与forUser(…)
方法匹配(我猜是因为userId
参数名)并忽略路由的{action}
部分
有没有办法避免这种行为并要求在URL中明确指定操作部分?我不完全理解您的问题。
/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
两件事结合起来。首先,这条路线:
config.Routes.MapHttpRoute(
"DefaultApiWithAction",
"api/v1/{controller}/{action}",
new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
没有“action”作为可选参数。您已将id
作为可选项(我假设为输入错误),但由于它不存在于路线中,您将无法获得仅一个补充段的匹配。只有包含控制器和操作两部分的URL才会通过此路由。此url:
/api/v1/projects?userId=1
…包含一个单独的段,并且不会。此路由以及缺少第二个组件的任何其他路由将默认为此路由:
config.Routes.MapHttpRoute(
"DefaultApiWithAction",
"api/v1/{controller}/{action}",
new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
…只接受控制器和可选ID。您需要重新格式化给定URL以获取操作参数,或者重写路由以使操作可选,并根据需要设置默认值。这一切都取决于您的应用程序体系结构,但总是在简单性方面出错。路线可能变得非常复杂——通常越简单越好
对于所需/可选的管线组件,请记住以下两点:
- 除非在匿名对象中将所有管段设置为可选,否则所有管段都是必需的
- 如果段具有默认值,也可以将其排除在外,该默认值是通过在匿名对象中以
的形式提供一个值来设置的placeholder=value
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
-like请求通过第一个路由发送到forUser(int-id)
方法。将userId
参数重命名为id
可以构造更干净的URL
显然,这种方法有一些局限性,但在我的具体案例中,这就是我所需要的。目的是使动作部分显式,这样URL才有意义。现在,我可以将任何内容替换为操作名称,它仍将用于用户操作。至于添加“id”参数,我同意它是有效的,但这并不完全是我一直在寻找的(因为某些操作可能有多个参数)。谢谢。
/api/v1/projects/ForUser/2
与/api/v1/projects/ForUser?userId=2
相同。要添加更多参数,只需执行/api/v1/projects/ForUser?userId=2&userName=andrew
不幸的是,似乎您弄错了,一段/api/v1/projects?userId
URL被路由到ForUser()
操作。我猜这是因为ForUser()
操作具有userId
参数,该参数与URL中的userId
参数相匹配。(我还编辑了这个问题并删除了误导性的部分)@AndrewKhmylov-我想可能是我解释得不够好。单段URL确实与ForUser操作匹配,但它这样做是因为它通过api/v1/{controller}/{id}
而不是api/v1/{controller}/{action}
。这是因为URL中没有指定任何操作。然后,它会做它想做的事情,很可能是通过查看ID,试图找到它认为最好的匹配项。如果希望它转到特定的匹配项,则需要更改路由以添加默认操作,或者将该操作添加到url,因为它当前不包含默认操作。