Using MVC and Web API controllers in ASP.NET Core

Photo by wu yi on Unsplash

Those familiar with ASP.NET will know that before the advent of ASP.NET Core we had two frameworks — MVC and Web API. When you wanted to return data responses in a format such as JSON you’d use a Web API controller.

To create a Web API controller in ASP.NET Web API 2, you’d create a controller that inherits from ApiController. This is a part of the System.Web.Http assembly.

Then, when you wanted to render a view, you’d use an MVC controller. To create an MVC controller in ASP.NET MVC, you’d create a controller that inherits from Controller, which is a part of the System.Web.Mvc assembly.

using System.Web.Http;
using System.Web.Mvc;

namespace MVC
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}

namespace WepApi
{
public class WebController : ApiController
{
public IHttpActionResult Index()
{
return Json(new { foo = "bar" });
}
}
}

With the release of ASP.NET Core, the ASP.NET MVC framework and ASP.NET Web API framework have been unified under the ASP.NET Core MVC framework. This has combined components such as controller, actions, model binding, filters, dependency injection, and routing.

Here we’re going to take a look at the different ways we can now create a controller in ASP.NET Core.

Controllers

When you create a new ASP.NET Core MVC application, you’ll notice that controllers are still put into the Controllers folder in the root of the application by default. In the Controllers folder you’ll have an example controller called HomeController that inherits from Controller. The inherited Controller class comes from the new Microsoft.AspNetCore.Mvc assembly.

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using UnifiedControllers.Models;

namespace UnifiedControllers.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}

public IActionResult About()
{
ViewData["Message"] = "Your application description page.";

return View();
}

public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";

return View();
}

public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

You’ll notice that the HomeController example above contains several actions with a return type of IActionResult. While I won’t go too much into the different types of results an action can return, it's worth noting that IActionResult is an interface and ActionResult is an abstract class that other action results inherit from.

If we look at the Index action method, we can see it returns a View (ViewResult), which should be familiar from the ASP.NET MVC controller example we discussed earlier. If we then change this action method to return an OkResult object — which matches the return type from our ASP.NET Web API 2 controller — add a [HttpGet] attribute, you’ll notice that when we build this code the compiler is happy. This is the power of the new ASP.NET Core MVC framework: allowing us to return a View (MVC) or Object (Web API) from a single unified controller.

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using UnifiedControllers.Models;

namespace UnifiedControllers.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return Ok();
}

public IActionResult About()
{
ViewData["Message"] = "Your application description page.";

return View();
}

public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";

return View();
}

public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

One of the new features in ASP.NET Core MVC allows us to create plain old CLR object classes (POCO) as controllers using built-in convention. This means our Controller class does not need to inherit from the abstract Controller class in the Microsoft.AspNetCore.Mvc assembly. Our Controller class must be public and the class name should be suffixed with “Controller”. Our Controller class must also be defined in an assembly that references one of the ASP.NET Core MVC assemblies such as Microsoft.AspNetCore.Mvc.

namespace UnifiedControllers.Controllers
{
public class HomeController
{
public string Index()
{
return "hello";
}
}
}

In the POCO controller example above, it is also possible to drop the “Controller” suffix by applying the [Controller] attribute to the top of our Controller class:

using Microsoft.AspNetCore.Mvc;

namespace UnifiedControllers.Controllers
{
[Controller]
public class Home
{
public string Index()
{
return "hello";
}
}
}

So what happens if you create a class with the “Controller” suffix but you don’t want it to be picked up as a POCO Controller? This is where the [NonController] attribute comes in. By applying the [NonController] attribute to a class with the “Controller” suffix it will not be picked up as a POCO controller.

Conclusion

I hope this has given you a basic understanding of how you can create MVC and Web API controllers using the new, unified approach in ASP.NET Core 2.

Resources

Handle requests with controllers in ASP.NET Core MVC
 Controller action return types in ASP.NET Core Web API
 Create a Web API with ASP.NET Core and Visual Studio Code


Originally published at carljackson.io on April 8, 2018.