12

Here is my routing configuration:

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

And, here is my controller:

public class ProductsController : ApiController
{
    [AcceptVerbs("Get")]
    public object GetProducts()
    {
       // return all products...
    }

    [AcceptVerbs("Get")]
    public object Product(string name)
    {
       // return the Product with the given name...
    }
}

When I try api/Products/GetProducts/, it works. api/Products/Product?name=test also works, but api/Products/Product/test does not work. What am I doing wrong?

UPDATE:

Here's what I get when I try api/Products/Product/test:

{
  "Message": "No HTTP resource was found that matches the request URI 'http://localhost:42676/api/Products/Product/test'.",
  "MessageDetail": "No action was found on the controller 'Products' that matches the request."
}

3 Answers 3

16

This is because of your routing settings and its default values. You have two choices.

1) By changing the route settings to match the Product() parameter to match the URI.

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

2) The other and recommended way is to use the correct method signature attribute.

public object Product([FromUri(Name = "id")]string name){
       // return the Product with the given name
}

This is because the method is expecting a parameter id when requesting api/Products/Product/test rather than looking for a name parameter.

Sign up to request clarification or add additional context in comments.

3 Comments

OK, it looks like you need to specify the name, like this: public object Product([FromUri(Name = "id")]string name).
Thanks for the recommended way!
worked for me! I wanted a different param in the string, but was defined as "id" in the webapiconfig file and your suggestion fixed it!! thanks much.
7

Based on your update:

Please note that WebApi works based on reflection this means that your curly braces {vars} must match the same name in your methods.

Therefore to match this api/Products/Product/test based on this template "api/{controller}/{action}/{id}" YOur method needs to be declare like this:

[ActionName("Product")]
[HttpGet]
public object Product(string id){
   return id;
}

Where the parameter string name was replaced by string id.

Here is my full sample:

public class ProductsController : ApiController
{
    [ActionName("GetProducts")]
    [HttpGet]
    public object GetProducts()
    {
        return "GetProducts";
    }
    [ActionName("Product")]
    [HttpGet]
    public object Product(string id)
    {
        return id;
    }
}

I tried using a totally different template:

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

But it worked fine on my end. Btw I additional removed [AcceptVerbs("Get")] and replaced them with [HttpGet]

2 Comments

@ataravati it works fine on my end. Are you getting an error?
Thanks for the explanation! I changed the parameter name, and it worked.
1

Your route is defining id as the parameter yet your method expects a name parameter. I prefer attribute routing if you can, then define /api/products/product/{name} on the Product method.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Comments

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.