Introduction
In this article, I am going to highlight the differences between ASP.NET MVC Controllers and Web API 2.0 Controllers, illustrating that with samples of code. However, I will emphasize more on Web API 2.0 as it is the latest evolution in Microsoft web services toolkit.
Advantages of Web API over MVC Controllers
API Controllers decouples code from serialization of results:
Every method in Web API will return data (JSON) without serialization.
However, in order to return JSON Data in MVC controllers, we will set the returned Action Result type to JsonResult and call the Json method on our object to ensure it is packaged in JSON.
- public JsonResult GetBooks()
- {
- var books = _repository.GetBooks();
- return Json(books, JsonRequestBehavior.AllowGet);
- }
Content negotiation: Components called formatters serializes the data returned to the client. They are automatically selected based on the content of the Accept header of the incoming request. You can either use built- in formatter such as: JSON and Xml or replace them by modifying the configuration.
Content negotiation plays a role in simplifying the development of method that might return the same raw data in a variety of formats, most typically XML and JSON.
Hosting:
Web API controllers can be hosted outside ASP.NET Runtime Stack and IIS Web server (things WCF was able to do) and are mainly used to build restful services hosted by specific organization and can be consumed by any device (android, IOS, web or windows application).
MVC controllers typically rely on MVC framework and are built with the view in mind (mainly returning HTML to the browser).
Now, we will dig deeper into code and implementation and check the key differences:
Controllers
MVC controllers uses the base class Controller which is defined in System.Web.Mvc while API uses ApiController which is defined in System.Web.Http
- public class BooksController: Controller
- {
- public ActionResult Details(int id)
- {
- var book = _repository.GetBook(id);
- if (book == null) returnnewHttpNotFoundResult();
-
- return View(book);
- }
- }
Web API will resolve our objects to the suitable format using content negotiation. In this example the book object is converted to JSON and sent back as a response to the incoming request:
- public class Books Controller: ApiController
- {
- public Book GetById(int id)
- {
- var book = _repository.GetBook(id);
- if (book == null) thrownewHttpResponseException(HttpStatusCode.NotFound);
- return book;
- }
- }
Web API Controllers by default dispatch to actions by HTTP verbs. Action names will start with one of the verb names (GET, PUT, POST, and DELETE). For instance, Get, GetBooks, and GetById will map to the verb name “GET”.
For actions that don’t match with one of those verbs, the default verb supported will be “POST”. Thus, we have to decorate all the actions that don’t meet with this naming conventions by one of the following attributes:
- HttpGet
- HttpPut
- HttpPost
- HttpDelete
MVC Controllers by default dispatch actions by name. A specific action name in a controller will directly map to the URL.
The two routes (routes configuration are explained later in this article) to the actions in the previous code will be the following:
- /api/books/{id}will route to ASP.NET Web API,where /api will occupy the URI space by default for all actions, followed by controller name and the parameter expected.
- /books/details/{id} will route to ASP.NET MVC (as ControllerName/ActionName/{parameter}).
Action Return Values
MVC controller methods returns objects of types of ActionResult that can produce variety of results. These are some of the predefined action results in ASP.NET MVC:
Action Result | Behavior |
ContentResult | Sends raw data to the browser. It serialize any content it receives. |
FileContentResult | Sends the content of the file to the browser. |
FileStreamResult | Sends the content of the file to the browser (which is represented using Stream object). |
HttpNotFoundResult | Sends HTTP 404 response code (Resource was not found). |
HttpUnauthorizedResult | Sends HTTP 401 response code (Unauthorized request). |
JavaScriptResult | Sends JavaScript content to the browser. |
JsonResult | Sends JSON result to the browser. |
ViewResult | Send HTML content to the browser and represents a page view. |
PartialResult | Sends HTML content to the browser that represents a part of the whole page view. |
On the other hand, Web API 2.0 can return:
- HttpResponseMessage:
Raw objects (when passing domain models) are converted automatically to the suitable format (JSON or XML) using Content Negotiation which is a Web API feature. However, it is difficult to return different representation of success and errors in the response and this will make unit testing more difficult.
- publicHttpResponseMessage Get()
- {
-
- IEnumerable < Book > books = _repository.GetBooks();
-
-
- HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, books);
- return response;
- }
- IHttpActionResult:
Introduced in Web API 2.0 and will simplify unit testing controllers by returning a value type of IHttpActionResult. The ApiController includes many methods that directly return those action Results which sounds like MVC controller.
- publicIHttpActionResult Get()
- {
-
- IEnumerable < Book > books = _repository.GetBooks();
- if (books == null)
- {
- return NotFound();
- }
-
- return Ok(books);
- }
The following are the methods in the ApiController that return action results:
Method | Behavior |
BadRequest | Returns an HTTP 400 (“Bad Request”) |
Conflict | Returns an HTTP 409 (“Conflict”) |
Content | Returns Content (which is automatically negotiated or specified by the developer as media type formatter or content type) |
Created | Returns an HTTP 201 |
InternalServerError | Returns an HTTP 500 (“Internal Server Error”) |
Json | Returns an HTTP 200 (“OK”) and provides the content formatted in JSON |
NotFound | Returns an HTTP 404 (“Not Found”) |
Ok | Returns an HTTP 200 (“OK”) |
Redirect | Returns an HTTP 302 (“Found”) |
ResponseMessage | Returns the provided HttpResponseMessage |
StatusCode | Returns a response with provided HTTP status code and an empty response body |
Unauthorized | Returns an HTTP 401 (“Unauthorized) |
Configuration
Web API 2.0 is designed not to have static global variables (as in traditional ASP.NET Applications where they share application configuration in Global.asax). Routes are defined in the WebApiConfig static class and puts its configurations into the HttpConfiguration object and its Route property.
- publicstaticclassWebApiConfig
- {
-
- public staticvoid Register(HttpConfiguration config)
- {
- config.Routes.MapHttpRoute(
- name: "DefaultApi",
- routeTemplate: "api/{controller}/{id}",
- defaults: new
- {
- id = RouteParameter.Optional
- }
- );
- }
- }
On the other hand, MVC routes are defined in the static RouteConfig class, directly against the
System.Web.RouteCollection. - public class RouteConfig
- {
- public staticvoid RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
-
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new
- {
- controller = "Home", action = "Index", id =
- UrlParameter.Optional
- }
- );
- }
- }
Now, let’s take a look on the
Global.asax file where we have to register our Web API Configuration by passing the parameter GlobalConfiguration.Configuration to the register method.
Also, you can see how RouteConfig can add the routes to the Route table for MVC.
- protected void Application_Start()
- {
- FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
-
-
- paramerter
-
- WebApiConfig.Register(GlobalConfiguration.Configuration);
- RouteConfig.RegisterRoutes(RouteTable.Routes);
- BundleConfig.RegisterBundles(BundleTable.Bundles)
- AuthConfig.RegisterAuth();
- }
Conclusion While MVC controllers can be consumed as services and do anything with additional coding, its main purpose is to build web HTML applications with some Ajax functions returning JSON data. On the other hand, Web API 2.0 is dedicated and specialized with transferring data and will be the optimal choice and the suitable development model that makes it easy to build RESTful services interface to different clients running on different platforms.