Web API路由-GET方法过载导致405方法不允许用于其他动词 [英] Web API Routing - Overloaded GET method causes 405 Method Not Allowed for other verbs

查看:67
本文介绍了Web API路由-GET方法过载导致405方法不允许用于其他动词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个API控制器,它支持用户对象的DELETE,GET,POST和PUT操作. GET-one操作可以通过其ID检索用户帐户.但是我也想通过用户名来获得用户.我为每种方法创建了单独的方法,由于可以同时获得两种方式的预期数据,因此看来效果很好.

I have an API controller that supports DELETE, GET, POST and PUT operations for an user object. The GET-one operation can retrieve a user account by their ID. But I also want to get the user by their UserName. I created separate methods for each and it seems to work fine as I can get the expected data both ways.

// GET: api/UserAccounts/5
[HttpGet]
[ResponseType(typeof(UserAccount))]
[Route("~/api/UserAccounts/{id:int}")]
public async Task<IHttpActionResult> GetUserAccount(int id) { ...  }

// GET: api/UserAccounts/JohnDoe
[HttpGet]
[ResponseType(typeof(UserAccount))]
[Route("~/api/UserAccounts/{userName}")]
public async Task<IHttpActionResult> GetUserAccount(string userName) { ... }

// DELETE: api/UseAccounts/5
[HttpDelete]
[ResponseType(typeof(UserAccount))]
public async Task<IHttpActionResult> DeleteUserAccount(int id) { ... }

// GET: api/UserAccounts
[HttpGet]
public IQueryable<UserAccount> GetUserAccounts() { ... }

// POST: api/UserAccounts
[HttpPost]
[ResponseType(typeof(UserAccount))]
public async Task<IHttpActionResult> PostUserAccount(UserAccount userAccount) { ... }

// PUT: api/UserAccounts/5
[HttpPut]
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutUserAccount(int id, UserAccount userAccount)

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

The problem is that whenever I attempt to do a DELETE, POST or PUT operation, I get a 405 - Method Not allowed response. If I comment out the GetUser(string) method, they all work.

我浏览了许多文章和文档,并且看到了在Route属性上使用RouteOrder属性的一些信息,但这没什么区别.

I looked through a bunch of articles and documentation and I saw something about using the RouteOrder property on the Route attribute, but that doesn't make any difference.

我的WebApiConfig具有以下代码:

My WebApiConfig has this code:

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

由于我正在为我的GetUser方法使用属性路由,因此我认为这应该可行.我正在为其他方法/动词使用默认路由.

Since I am using attribute routing for my GetUser methods I would think this should be working. I'm using the default routes for the other methods/verbs.

肯定有一种方法可以完成这项工作,对吧?

Surely there is a way to make this work, right?

更新:

我仍然遇到此问题.我删除了GET(字符串)操作并删除了所有属性路由,因为其他操作都使用DefaultApi路由.所有标准操作均正常进行.但是,如果引入GET(字符串)操作,则仅GET-all操作有效. GET(int)版本不返回任何响应,可能是因为API无法确定要使用的GET重载.所有其他操作都返回405方法不允许.为了解决这个问题,我向GET(int)和GET(string)方法添加了一个属性路由,这些方法现在可以使用,但是DELETE,POST和PUT操作返回405 Method Not Allowed.

I'm still experiencing this issue. I removed the GET (string) operation and removed all the attribute routes since the other operations use the DefaultApi route. All the standard operations work. However, if I introduce a GET (string) operation, only the GET-all operation works. The GET (int) version returns no response, presumably because the API cannot determine which GET overload to use. All other operations return 405 Method Not Allowed. To get around this I added an attribute route to the GET (int) and GET (string) methods and those now work, but the DELETE, POST and PUT operations return 405 Method Not Allowed.

如果我将属性路由添加到所有方法,则除POST操作外,其他所有功能均有效.在这种情况下,我得到405 Method Not Allowed.这是带有属性路由的方法签名:

If I add attribute routes to all the methods, everything works except the POST operation. In that case I get 405 Method Not Allowed. Here are the methods signatures with the attribute routes:

[HttpDelete]
[ResponseType(typeof(UserAccount))]
[Route("~/api/UserAccounts/{id:int}")]
public async Task<IHttpActionResult> DeleteUserAccount(int id)

[HttpGet]
[ResponseType(typeof(UserAccount))]
[Route("~/api/UserAccounts/{id:int}")]
public async Task<IHttpActionResult> GetUserAccount(int id)

[HttpGet]
[ResponseType(typeof(EnrollmentApiAccountDto))]
[Route("~/api/UserAccounts/{userName}")]
public async Task<IHttpActionResult> GetUserAccount(string userName)

[HttpGet]
[Route("~/api/UserAccounts")]
public IQueryable<UserAccount> GetUserAccounts()

[HttpPost]
[ResponseType(typeof(UserAccount))]
[Route("~/api/UserAccounts")]
public async Task<IHttpActionResult> PostUserAccount(UserAccount userAccount)

[HttpPut]
[ResponseType(typeof(void))]
[Route("~/api/UserAccounts/{id:int}")]
public async Task<IHttpActionResult> PutUserAccount(int id, UserAccount userAccount)

对GET(字符串)属性路由没有任何限制.我不能使用{username:alpha},因为用户名可能包含数字.

There is no constraint on the GET (string) attribute route. I can't use {username:alpha} because the username might contain digits.

我需要支持GET by userName操作,因为我需要它来进行用户身份验证.但是除非我能弄清楚,否则可能不得不创建其他控制器来支持该操作.我不愿意.

I need to support the GET by userName operation because I need it for user authentication. But unless I can figure this out, I may have to create a different controller just to support that action. I prefer not to.

推荐答案

我之前没有提到,但是有两个客户端正在使用此API控制器.

I didn't mention this before, but there are two clients using this API controller.

第一个是ASP.NET Web窗体应用程序.使用路由属性修饰所有方法后,所有操作均按预期进行.对于POST操作,它要发布到的路由是/api/UserAccounts.这是我期望的,因为ID参数不是必需的.

The first is an ASP.NET web forms application. With all the methods decorated with route attributes, all operations work as expected. In the case of the POST operation, the route it is posting to is /api/UserAccounts. This is what I expected as the ID argument is not necessary.

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

The second is an AngularJS application. The way the resource is configured, the ID parameter is sent for POST's, meaning the route being posted to is /api/UserAccounts/0. This seems to be the problem. (Oddly a GET request doesn't pass the ID when I want to get all records, only when I want one record.)

我注意到使用Fiddler检查请求/响应.由于某种原因,Fiddler无法捕获Web窗体应用程序和API之间的流量,但是我知道代码是在没有ID参数的情况下组成POST请求的,因为这不是必需的.

I noticed this using Fiddler to inspect the request/response. For some reason, Fiddler was not able to capture the traffic between the web forms application and the API, but I know the code is composing the POST request without the ID parameter because it is not necessary.

因此,我然后使用Fiddler使用之前失败的相同有效负载向/api/UserAccounts组成一个新的POST请求,当我提交该请求时,PostUserAccount方法控制器将执行并创建数据库记录.这就是我的期望.

Therefore, I then used Fiddler to compose a new POST request to /api/UserAccounts using the same payload that failed before, and when I submitted it, the PostUserAccount method controller executed and created the database record. This is what I expected.

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

However it must be noted that I have many other controllers that are called by my AngularJS application using this pattern of route (appending the ID of 0 for POST requests) and there is no problem. Apparently the addition of an overload for the GET operation that takes a string argument messes this up. I now need to figure out how to get my AngularJS application to not pass the ID argument for POST methods. I'll create another question to deal with that issue.

这篇关于Web API路由-GET方法过载导致405方法不允许用于其他动词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆