2
votes

I am having some trouble understanding how Web API 2 handles routing.

  • I have created a PostsController that works just fine in terms of the standard actions, GET, POST, etc.
  • I tried to add a custom route that is a PUT action called Save() that takes a model as an argument.
  • I added [HttpPut] and [Route("save")] in front of the custom route. I also modified the WebAPIConfig.cs to handle the pattern api/{controller}/{id}/{action}
  • However, if I go to http://localhost:58385/api/posts/2/save in Postman (with PUT) I get an error message along the lines of No action was found on the controller 'Posts' that matches the name 'save'. Essentially a glorified 404.
  • If i change the route to be [Route("{id}/save")] the resulting error remains.

What am I doing incorrectly?

WebAPIConfig.cs

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

PostController.cs

// GET: api/Posts
public IHttpActionResult Get()
{
    PostsStore store = new PostsStore();
    var AsyncResult = store.GetPosts();
    return Ok(AsyncResult);
}

// GET: api/Posts/5
public IHttpActionResult Get(string slug)
{
    PostsStore store = new PostsStore();
    var AsyncResult = store.GetBySlug(slug);
    return Ok(AsyncResult);
}

// POST: api/Posts
public IHttpActionResult Post(Post post)
{
    PostsStore store = new PostsStore();
    ResponseResult AsyncResult = store.Create(post);
    return Ok(AsyncResult);
}

    // PUT: api/Posts/5 DELETED to make sure I wasn't hitting some sort of precedent issue.
    //public IHttpActionResult Put(Post post)
   // {

       //     return Ok();
    //}

[HttpPut]
[Route("save")]
public IHttpActionResult Save(Post post)
{
    PostsStore store = new PostsStore();
    ResponseResult AsyncResponse = store.Save(post);
    return Ok(AsyncResponse); 
}
1
Use the RouteDebugger NuGet package and it will tell you exactly what route the routing engine is looking for, where did it look to find the matching route and why it could not find it. The routing engine can not be described in a few words. There is a lot to be said. - CodingYoshi

1 Answers

2
votes

If using [Route] attribute then that is attribute routing as apposed to the convention-based routing that you configure. You would need to also enable attribute routing.

//WebAPIConfig.cs

// enable attribute routing
config.MapHttpAttributeRoutes();

//...add other convention-based routes

And also the route template would have to properly set.

//PostController.cs

[HttpPut]
[Route("api/posts/{id}/save")] // Matches PUT api/posts/2/save
public IHttpActionResult Save(int id, [FromBody]Post post) {
    PostsStore store = new PostsStore();
    ResponseResult AsyncResponse = store.Save(post);
    return Ok(AsyncResponse);    
}

Reference Attribute Routing in ASP.NET Web API 2