0

I have two API endpoints defined as such:

[Route("create")]
[HttpPost]
[ResponseType(typeof(User))]
public async Task<IHttpActionResult> CreateUser(User user)

[Route("login")]
[HttpPost]
[ResponseType(typeof (User))]
public async Task<IHttpActionResult> Login(string email, string password)

And the controller defined as

[RoutePrefix("api/users")]
public class UserController : ApiController

When I call it with this information (both in plain chrome, my app and the Postman application)

POST /api/users/login HTTP/1.1
Host: mysite.azurewebsites.net
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded

email=somemail&password=somepw

I receive a 404:

{
    "Message": "No HTTP resource was found that matches the request URI 'http://mysite.azurewebsites.net/api/users/login'.",
    "MessageDetail": "No action was found on the controller 'User' that matches the request."
}

It does work for another route which I can call with /api/users/1:

[Route("{id:int}")]
[HttpGet]
[ResponseType(typeof(User))]
public async Task<IHttpActionResult> GetUser(int? id)

Can't I explicitly define such endpoints? I tried creating a custom route but this made no difference (I placed this before the default route and after calling config.MapHttpAttributeRoutes()).

config.Routes.MapHttpRoute(
      name: "Login",
      routeTemplate: "api/users/login",
      defaults: new { controller = "User", action = "Login" }
);

Note that explicitly defining the route as [Route("~api/users/login")] didn't work either.

I have also noticed that routes in my other controller don't seem to work anymore. More specifically I have these definitions:

[RoutePrefix("api/movies")]
public class MovieController : BaseController

[Route("~api/genres")]
[HttpGet]
[ResponseType(typeof(IEnumerable<Genre>))]
public IHttpActionResult GetGenres()

[Route("~api/genres/{id:int}")]
[HttpGet]
[ResponseType(typeof(IEnumerable<MovieResult>))]
public IHttpActionResult GetMoviesForGenre(int id)

[Route("{id:int}")]
[HttpGet]
[ResponseType(typeof(Movie))]
public IHttpActionResult GetMovieDetails(int id)

Of these options, only a call to /api/movies/16 succeeds, the others return

No type was found that matches the controller named 'genres'.

Is there something elementary I'm overlooking?

I have made the genre routes available again by changing them to genres and genres/{id:int} and adding this route

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

but I would assume that this shouldn't be necessary. For some reason the request to /api/movies/genres works while /api/users/login doesn't. I did notice that creating a GET method with URI /api/users/genres DOES work so I believe it must have something to do with that. Why won't it find my POST-methods?

1 Answer 1

2

It looks like there are lots of moving pieces here so it's hard to figure out exactly what will fix all the problems. But here are a couple of issues to address...

Web API (unlike MVC) can only have one parameter read from the request body. So to make your Login action work, try to create a LoginInfo class...

public class LoginInfo
{
    public string email { get; set; }
    public string password { get; set; }
}

And change the Login method to...

public async Task<IHttpActionResult> Login([FromBody]LoginInfo loginInfo)

The issues with the genres appear to be the incorrect usage of ~ in the attribute routing (should be ~/). Try...

[Route("~/api/genres")]

and

[Route("~/api/genres/{id:int}")]
Sign up to request clarification or add additional context in comments.

1 Comment

I appreciate the reply! I actually solved it myself earlier and just about finished writing my answer when I had to leave my desk for a while. Indeed, the [FromBody] annotation with a single parameter was the solution (see here) so I'll just accept your answer instead. I'll also take a look into that tilde; I temporarily fixed that by simply using a standard route.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.