How to add Web API controller to an existing ASP.NET Core MVC?

Alex G. picture Alex G. · Jul 5, 2017 · Viewed 12.1k times · Source

I created a project using the default ASP.NET Core MVC template. I would like to also create a RESTful API under /api/{Controller}. I added a new Web API controller (standard Web API controller class template) but I can't call it. I get an error saying that the page cannot be found. I tried adding a route in Startup.cs but it doesn't do anything:

app.UseMvc(routes =>
{
    routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapRoute(name: "api", template: "api/{controller=Admin}");
});

EDIT:

Like I said, it's all default templates. Here's the Web API Controller that I added:

[Route("api/[controller]")]
public class AdminController : Controller
{                
    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

Answer

Nkosi picture Nkosi · Jul 5, 2017

Two things.

First, when using convention-based routing, more specific routes should come before more generic routes to avoid route conflicts.

app.UseMvc(routes =>
{
    routes.MapRoute(name: "api", template: "api/{controller=Admin}");
    routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});

Secondly, you are already using attribute routeing on the controller so should have been able to route to the controller except for the fact that you do not have a route template on the controller that would accept /api/{Controller}

That would require a default route

[Route("api/[controller]")]
public class AdminController : Controller {

    [HttpGet("")] //Matches GET api/admin <-- Would also work with [HttpGet]
    public IActionResult Get() {
        return Ok();
    }

    [HttpGet("{id}")] //Matches GET api/admin/5
    public IActionResult Get(int id) {
        return Ok("value");
    }    

    //...other code removed for brevity
}