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)
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.
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.
My WebApiConfig has this code:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
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?
UPDATE:
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.
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)
There is no constraint on the GET (string) attribute route. I can't use {username:alpha} because the username might contain digits.
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.
[HttpGet]
as an attribute. Don't you need either a) the rest of the http verb attributes, or b) no verb attributes (which would allow PATCH as well)? – gunr2171[Route(...)]
attribute to all your other methods. I have a feeling that actions that don't have a route attribute are using the "DefaultApi" route. – gunr2171