0

I have applied attribute routing on my controller and it'srouting to wrong action. I don't know where I am getting it wrong.

Here is my controller:

using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Description;
using System.Linq;
using System;

namespace Iboo.API.Controllers
{
    public class ClientsController : ApiController
    {
        private readonly IClientRepository _repository;

        public ClientsController(IClientRepository repository)
        {
            _repository = repository;
        }

        // GET: api/Clients
        [Route("api/v1/clients")]
        public IEnumerable<Client> Get()
        {

           //code
        }


        // GET: api/Clients/5
        [HttpGet]
        [ResponseType(typeof(Client))]
        [Route("api/v1/clients/get/{id}")]
        public IHttpActionResult GetClientById(int id)
        {
            //code
        }

        // GET: api/Clients/5
        [HttpGet]
        [ResponseType(typeof(string))]
        [Route("api/v1/clients/{id}/emailid")]
        public IHttpActionResult GetClientEmailId(int id)
        {
            //code
        }        
    }
}

I am specifically interested in the GetClientEmailId method. Below is my WebApiConfig

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services
    var container = new UnityContainer();
    container.RegisterType<IClientRepository, ClientRepository>(new 
    HierarchicalLifetimeManager());


    // Web API routes
    config.MapHttpAttributeRoutes();

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

My Global.asax.cs is as follows

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.

If I try http://localhost:54919/api/v1/clients/1/getemailid I am getting a 404 error.

I am not sure as to what I'm getting wrong.

Edgias
  • 77
  • 3
  • 10
  • 2
    When you say "it's not working"... what do you mean? do you get an error? if so, what's it say? does it route to an unexpected place? if so, where? – Simon Jul 18 '17 at 11:50
  • 1
    @Munhu Can we see the code that is calling the GetClientEmailId method? – swatsonpicken Jul 18 '17 at 12:02
  • 1
    Questions seeking debugging help ("**why isn't this code working?**") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it **in the question itself**. Questions without **a clear problem statement** are not useful to other readers. See: How to create a [mcve]. – Nkosi Jul 18 '17 at 12:08
  • I am testing using the browser. I want to access http://localhost:54919/api/v1/clients/?id=1/getemailid but it's routing to the wrong action. – Edgias Jul 18 '17 at 12:27
  • @Munhu you are calling the wrong URLs according to routes on the actions. you get 404 because the URL you call does not match to any of the route templates you have on your actions – Nkosi Jul 18 '17 at 12:29
  • Did you try `http://localhost:54919/api/v1/clients/get/1` and `http://localhost:54919/api/v1/clients/1/emailid` ? – Chetan Jul 18 '17 at 12:32

3 Answers3

0

You can try using the route prefix on the controller.

[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController
{
    // GET: api/Clients/5
    [ResponseType(typeof(string))]
    [Route("{id:int}/emailid"),HttpGet]
    public IHttpActionResult GetClientEmailId(int id)
    {
        //code
    }     
}
Ross Bush
  • 14,648
  • 2
  • 32
  • 55
0

You said:

In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.

From the way your routes are set up, it looks like you need to go to http://localhost:54919/api/v1/client/1/emailid to get to the route you want

To explain the difference, when you call http://localhost:54919/api/v1/clients/?id=1/getemailid the route that would match that is something like:

[Route("api/v1/clients")]
public IHttpActionResult GetClientEmailId(string id)
{
    //code
}

because you've added the id parameter as a querystring parameter. In this case, the id argument would have a value of 1/getemailid which doesn't make much sense.

by using the route parameters (by replacing ?id=1/getemailid with 1/emailid) you will actually match the route you want to

Simon
  • 2,810
  • 2
  • 18
  • 23
0

You are calling the wrong URLs according to routes on the actions. you get 404 because the URL you call does not match to any of the route templates you have on your actions

[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController {
    //...other code removed for brevity

    [HttpGet]
    [Route("")] //Matches GET api/v1/Clients
    public IHttpActionResult Get() {
       //code
    }

    [HttpGet]
    [ResponseType(typeof(Client))]
    [Route("{id:int}")] //Matches GET api/v1/Clients/5
    public IHttpActionResult GetClientById(int id) {
        //code
    }

    [HttpGet]
    [ResponseType(typeof(string))]
    [Route("{id:int}/emailid")] //Matches GET api/v1/Clients/5/emailid
    public IHttpActionResult GetClientEmailId(int id) {
        //code
    }        
}

Take note of the expected URLs in the comments

You should also read up on Attribute Routing in ASP.NET Web API 2 to get a better understanding of how to do attribute-routing.

Nkosi
  • 235,767
  • 35
  • 427
  • 472