Web API路由 – 重载的GET方法导致其他动词不允许405方法

我有一个API控制器,支持用户对象的DELETE,GET,POST和PUT操作。 GET-one操作可以通过其ID来检索用户帐户。 但我也想通过他们的UserName获取用户。 我为每个创建了单独的方法,它似乎工作正常,因为我可以通过两种方式获得预期的数据。

// GET: api/UserAccounts/5 [HttpGet] [ResponseType(typeof(UserAccount))] [Route("~/api/UserAccounts/{id:int}")] public async Task GetUserAccount(int id) { ... } // GET: api/UserAccounts/JohnDoe [HttpGet] [ResponseType(typeof(UserAccount))] [Route("~/api/UserAccounts/{userName}")] public async Task GetUserAccount(string userName) { ... } // DELETE: api/UseAccounts/5 [HttpDelete] [ResponseType(typeof(UserAccount))] public async Task DeleteUserAccount(int id) { ... } // GET: api/UserAccounts [HttpGet] public IQueryable GetUserAccounts() { ... } // POST: api/UserAccounts [HttpPost] [ResponseType(typeof(UserAccount))] public async Task PostUserAccount(UserAccount userAccount) { ... } // PUT: api/UserAccounts/5 [HttpPut] [ResponseType(typeof(void))] public async Task PutUserAccount(int id, UserAccount userAccount) 

问题是每当我尝试执行DELETE,POST或PUT操作时,我都会得到405 – Method Not allowed响应。 如果我注释掉GetUser(string)方法,它们都可以工作。

我查看了一堆文章和文档,我看到了一些关于在Route属性上使用RouteOrder属性的内容,但这没有任何区别。

我的WebApiConfig有这个代码:

 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); 

由于我使用属性路由为我的GetUser方法,我认为这应该工作。 我正在使用其他方法/动词的默认路由。

当然有办法让这项工作,对吧?

更新:

我还在遇到这个问题。 我删除了GET(字符串)操作并删除了所有属性路由,因为其他操作使用DefaultApi路由。 所有标准操作都有效。 但是,如果我引入GET(字符串)操作,则只有GET-all操作有效。 GET(int)版本没有返回响应,可能是因为API无法确定要使用哪个GET重载。 所有其他操作返回405 Method Not Allowed。 为了解决这个问题,我添加了一个属性路由到GET(int)和GET(字符串)方法,这些方法现在可以工作,但是DELETE,POST和PUT操作返回405 Method Not Allowed。

如果我将属性路由添加到所有方法,除了POST操作之外,一切都有效。 在那种情况下,我得到405方法不允许。 以下是具有属性路由的方法签名:

 [HttpDelete] [ResponseType(typeof(UserAccount))] [Route("~/api/UserAccounts/{id:int}")] public async Task DeleteUserAccount(int id) [HttpGet] [ResponseType(typeof(UserAccount))] [Route("~/api/UserAccounts/{id:int}")] public async Task GetUserAccount(int id) [HttpGet] [ResponseType(typeof(EnrollmentApiAccountDto))] [Route("~/api/UserAccounts/{userName}")] public async Task GetUserAccount(string userName) [HttpGet] [Route("~/api/UserAccounts")] public IQueryable GetUserAccounts() [HttpPost] [ResponseType(typeof(UserAccount))] [Route("~/api/UserAccounts")] public async Task PostUserAccount(UserAccount userAccount) [HttpPut] [ResponseType(typeof(void))] [Route("~/api/UserAccounts/{id:int}")] public async Task PutUserAccount(int id, UserAccount userAccount) 

GET(字符串)属性路由没有约束。 我无法使用{username:alpha},因为用户名可能包含数字。

我需要通过userName操作支持GET,因为我需要它来进行用户身份validation。 但除非我能解决这个问题,否则我可能需要创建一个不同的控制器来支持该操作。 我不喜欢。

我之前没有提到过,但有两个客户端使用这个API控制器。

第一个是ASP.NET Web表单应用程序。 使用路径属性修饰的所有方法,所有操作都按预期工作。 在POST操作的情况下,它发布到的路由是/ api / UserAccounts。 这是我所期望的,因为ID参数不是必需的。

第二个是AngularJS应用程序。 配置资源的方式是为POST发送ID参数,这意味着发布到的路由是/ api / UserAccounts / 0。 这似乎是个问题。 (奇怪的是,当我想要获取所有记录时,只有当我想要一条记录时,GET请求才会传递ID。)

我注意到这使用Fiddler来检查请求/响应。 出于某种原因,Fiddler无法捕获Web表单应用程序和API之间的流量,但我知道代码组成的POST请求没有ID参数,因为没有必要。

因此,我随后使用Fiddler使用之前失败的相同有效负载组成对/ api / UserAccounts的新POST请求,当我提交它时,PostUserAccount方法控制器执行并创建数据库记录。 这是我的预期。

但是必须注意的是,我有许多其他控制器,我的AngularJS应用程序使用这种路由模式调用(为POST请求附加ID为0)并且没有问题。 显然,为GET操作添加了一个带有字符串参数的重载会使其变得混乱。 我现在需要弄清楚如何让我的AngularJS应用程序不传递POST方法的ID参数。 我将创建另一个问题来处理这个问题。