4
votes

I have spent some considerable time trying to get Web API attribute routing working, and all I am getting are 404 errors no matter what I try.

I have a simple ApiController that tries to define a HttpGet at api/hello/{number} and hello/{number}:

public class HelloController : ApiController
{
    public class Hello
    {
        public string user { get; set; }
        public string password { get; set; }
    }

    [Route("api/hello/{number}")]
    [Route("hello/{number}")]
    [HttpGet]
    public IEnumerable<Hello> GetStuff(int number)
    {
        var response = Request.CreateResponse(HttpStatusCode.Created, number);
        return null;
    }

    [Route("api/hello")]
    [HttpPost]
    public HttpResponseMessage PostHello(Hello value) 
    {
        var response = Request.CreateResponse(HttpStatusCode.Created, value);
        return response;
    }
}

I have this as my RouteConfig, enabling attribute routing:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

WebAPIConfig:

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

Finally, here is my Application_Start() where I register the WebApiConfig:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }

Does anyone see something I am missing? I get 404 errors (unable to hit a breakpoint in GetStuff()) for all of the following:

  • http://localhost/api/hello
  • http://localhost/api/hello/1
  • http://localhost/hello
  • http://localhost/hello/2

My post does not work either.

2
Shouldn't the id in route config be changed to number >? and why would you receive any parameter for api/hello? - Tushar
even if I remove the parameter, remove number completely, I still get 404 errors - gnychis

2 Answers

4
votes

Your MVC routes are taking precedence over your API routes. Because you are using a catch all route for the MVC side ("{controller}/{action}/{id}"), and it is being registered first, your routing will always look for an mvc controller named api or hello, because that's the route it matched.

Try moving your api registration above your MVC route registration in your Global.asax:

GlobalConfiguration.Configure(WebApiConfig.Register);
//then
RouteConfig.RegisterRoutes(RouteTable.Routes);
1
votes

Set a route prefix at the class level. Then set the route at the function level.

[RoutePrefix("api/hello")]
public class HelloController : ApiController
{
    [Route("getstuff/{number}")]
    public IEnumerable<Hello> GetStuff(int number)
    {
    }
}

Then call with /api/hello/getstuff/1