← Back to articles

ASP.NET Core MVC with /api/-area

Part of my ASP.NET Core recipe series: carving out an /api/-area in an MVC project so pages and API endpoints live cleanly side by side.

Tedd

Having MVC pages and API in the same solution can be beneficial. Projects may share a lot of boilerplate code and settings, is easier to maintain and can access API functions directly through DI (if controllers are registered there) instead of going via HTTP. But you may want to separate both URL and code so it is clear what is MVC and what is API.

Setting up areas

If you are using Visual Studio: Right-click project, select Add, select Area, enter “api”. This will create empty folder Areas\\api with MVC folder structure under it. It also pops up a text file asking you to make a change to the default MapRoute in Startup.cs.

If using Rider or other tool you may have to do it manually. Create folders in root:

  • Areas\\api\\Controllers
  • Areas\\api\\Models

Then in addition to your existing default route, you should add areas route in Startup.cs.

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

Adding Api controller

Again, if you are using Visual Studio, simply:

  • Right click “Areas\\Api\\Controllers”
  • Select “Add->Controller”
  • Select “API Controller - Empty” and name it, for this test I named it TestController

If you are using Rider or other tool you may have either create manually (see bellow for sample) or create Controller and modify it a bit. Change “Controller” to “ControllerBase”, add [ApiController] tag and set route.

In the newly created TestController.cs we need to specify route, specifically [action]. This can be done in class route definition, or per method. With a few example methods the class looks like this:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
 [Route("[action]/{a}/{b}")]
 [HttpGet]
 public string Concat(string a, string b)
 {
 return a + b;
 }

 [Route("[action]")]
 [HttpGet]
 public string GetOnly()
 {
 return "Can't post here";
 }

 [Route("Dual")]
 [HttpGet]
 public string DualGet()
 {
 return "You used GET";
 }

 [Route("Dual")]
 [HttpPost]
 public string DualPost()
 {
 return "You used POST";
 }

 [Route("[action]/{id}")]
 [HttpGet]
 public IActionResult ReturnHttpCode(int id)
 {
 if (id==0)
 return NotFound();

 return Ok("You found it!");
 }
} 

Test

You can then test this by starting solution and opening browser to https://localhost:44378/Api/Test/Concat/123/abc. Note that you must change port number to whatever port your solution is running on.

Written by Tedd · Oslo, Norway

Updated 25 Jun 2019

Follow the journal via RSS