MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

cannot resolve routing for action

I´m creating a Web-API with a controller like this:

public class ProductsController : ApiController
{
    private readonly Product[] m_products = {
        new Product {Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1},
        new Product {Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M},
        new Product {Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M}
    };

    public IEnumerable<Product> GetAllProducts()
    {
        return this.m_products;
    }


    [HttpGet]
    [ActionName("ById")]
    public IHttpActionResult GetProductById(int id)
    {
        var product = this.m_products.FirstOrDefault(x => x.Id == id);
        return product == null ? (IHttpActionResult) NotFound() : Ok(product);
    }

    [HttpGet]
    [ActionName("ByName")]
    public IHttpActionResult GetProductByName(string name)
    {
        var product = this.m_products.FirstOrDefault(x => x.Name == name);
        return product == null ? (IHttpActionResult) NotFound() : Ok(product);
    }
}

Within my WebApiConfig I have this:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

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

So in fact I´m trying to have two actions on my ProductController. However I can´t seem to get the second one to work. Thuis when I run myServer/api/products/ById/1 I get the first element from my list. However when I try myServer/api/products/ByName/Hammer I get an Http-error not found (404). I also tried the URL in lowercase with the same result.

Upvotes: 2

Views: 417

Answers (3)

maccettura
maccettura

Reputation: 10818

Your RouteConfig is defined as this:

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

But your ByName action takes a name parameter, not id.

You need to create a route that takes a name parameter.

You can do this easily by decorating your action:

[Route("ByName/{name}")]
public IHttpActionResult GetProductByName(string name)

I forgot you also need to include the RoutePrefix attribute on your controller.

[RoutePrefix("api/products")]
public class ProductsController : ApiController
{

Upvotes: 3

NamiraJV
NamiraJV

Reputation: 666

One of the options is to use Route attribute to specify routes to your resources. For your case it would look like this:

[RoutePrefix("api/Products")]
public class ProductsController : ApiController
{
    private readonly Product[] m_products = {
        new Product {Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1},
        new Product {Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M},
        new Product {Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M}
    };

    //GET api/products
    [HttpGet]
    [Route("")]
    public IEnumerable<Product> GetAllProducts()
    {
        return this.m_products;
    }

    //GET api/products/ById/1
    [HttpGet]
    [Route("ById/{id:int}")]
    public IHttpActionResult GetProductById(int id)
    {
        var product = this.m_products.FirstOrDefault(x => x.Id == id);
        return product == null ? (IHttpActionResult) NotFound() : Ok(product);
    }

    //GET api/products/ByName/Hammer
    [HttpGet]
    [Route("ByName/{name}")]
    public IHttpActionResult GetProductByName(string name)
    {
        var product = this.m_products.FirstOrDefault(x => x.Name == name);
        return product == null ? (IHttpActionResult) NotFound() : Ok(product);
    }
}

Upvotes: 3

Ehsan Sajjad
Ehsan Sajjad

Reputation: 62488

You can explicitly specify the pattern using Route() attribute for your action method like:

[HttpGet]
[ActionName("ByName")]
[Route("api/Products/ByName/{name}")]
public IHttpActionResult GetProductByName(string name)
{
    var product = this.m_products.FirstOrDefault(x => x.Name == name);
    return product == null ? (IHttpActionResult) NotFound() : Ok(product);
}

Please refer to the official documentation for more details.

Upvotes: 2

Related Questions