Hola a todos, aunque ya hace un buen tiempo que ha salido la versión 2 de Web API, una de las características que más me ha gustado es el nuevo tipo de routing que tenemos disponible conocido como routing por atributos (attribute routing), el cual básicamente permite definir el routing desde nuestros controladores, además que nos ayuda a solucionar problemas cotidianos que teníamos en versiones anteriores.



Partamos de un sencillo controlador como el siguiente:


public class CustomerController : ApiController
{
    readonly List<Customer> customers = new List<Customer>()
    {
        new Customer() { Id = 1, Name = "Walker", LastName = "Sosa" },
        new Customer() { Id = 2, Name = "Reese", LastName = "Todd" },
        new Customer() { Id = 3, Name = "Jason", LastName = "Woodward" },
        new Customer() { Id = 4, Name = "Samuel", LastName = "Cole" },
        new Customer() { Id = 5, Name = "Harding", LastName = "Mcgowan" }
    };

    public IEnumerable<Customer> Get()
    {
        return customers;
    }

    public Customer GetById(int id)
    {
        return customers.Where(c => c.Id == id).FirstOrDefault();
    }

    public Customer GetByName(string name)
    {
        return customers.Where(c => c.Name.ToLower().Contains(name.ToLower())).FirstOrDefault();
    }
}

Y la clase Customer


public class Customer
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string LastName { get; set; }
}

Ahora si probamos el servicio, tenemos un problema si hacemos una petición del tipo /api/customer/sam:

routing



Para solucionarlo vamos a aprovechar el nuevo tipo de routing por atributos disponible desde Web API 2 y superior, lo primero entonces es habilitarlo, para ello añadimos la línea config.MapHttpAttributeRoutes(); en el archivo que defina nuestras rutas, generalmente en la carpeta App_Start, clase WebApiConfig, por lo tanto la clase ahora se ve:


public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

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

El siguiente paso es decorar nuestro controlador con el atributoRoutePrefixAttribute, en este caso*[RoutePrefixAttribute(“api/customertask”)], *este atributo permite definir un nombre diferente al nombre del controlador para ser utilizado:


[RoutePrefixAttribute("api/customertask")]
public class CustomerController : ApiController
{
    ...
}

Para los métodos GetById y GetByName usamos el atributo Route:


[Route("{id:int}")]
public Customer GetById(int id)
{
    return customers.Where(c => c.Id == id).FirstOrDefault();
}

[Route("{name:alpha}")]
public Customer GetByName(string name)
{
    return customers.Where(c => c.Name.ToLower().Contains(name.ToLower())).FirstOrDefault();
}

Finalmente nuestro controlador quedaría:


[Route("{id:int}")]
public Customer GetById(int id)
{
    return customers.Where(c => c.Id == id).FirstOrDefault();
}

[Route("{name:alpha}")]
public Customer GetByName(string name)
{
    return customers.Where(c => c.Name.ToLower().Contains(name.ToLower())).FirstOrDefault();
}

Luego de los cambios, las siguientes llamados funcionan sin problema:

  • http:///api/customertask -> Método Get()
  • http:///api/customertask/2 -> Método GetById(int id)
  • http:///api/customertask/sam -> Método GetByName(string name)

Si quieren profundizar en el tema les recomiendo el siguiente link: Attribute Routing in Web API 2

Espero les sea de utilidad, saludos!