Reputation: 37000
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
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
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
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