The ASP.NET Web API is a framework that you can make use of to build web services that use HTTP as the protocol. You can use the ASP.NET Web API to return data based on the data requested by the client; that is, you can return JSON or XML as the format of the data.
The ASP.NET Framework runs on top of the managed environment of the .NET Framework.
The Model, View, and Controller (MVC) architectural pattern is used to separate the concerns of an application to facilitate testing, ease the process of maintenance of the application's code, and to provide better support for change. The model represents the application's data and the business objects; the view is the presentation layer component, and the controller binds the Model and the View together. The following figure illustrates the components of Model View architecture:
The ASP.NET Web API is a lightweight web-based architecture that uses HTTP as the application protocol. Routing in the ASP.NET Web API works a bit differently compared to the way it works in ASP.NET MVC. The basic difference between routing in MVC and routing in a Web API is that Web API uses the HTTP method, and not the URI path, to select the action. The Web API Framework uses a routing table to determine which action is to be invoked for a particular request. You need to specify the routing parameters in the WebApiConfig.cs
file that resides in the App_Start
directory.
Here's an example that shows how routing is configured:
routes.MapHttpRoute( name: "Packt API Default", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
The following code snippet illustrates how routing is configured by action names:
routes.MapHttpRoute( name: "PacktActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );
The ASP.NET Web API generates structured data such as JSON and XML as responses. It can route the incoming requests to the actions based on HTTP verbs and not only action names. Also, the ASP.NET Web API can be hosted outside of the ASP.NET runtime environment and the IIS Web Server context.
Routing in the ASP.NET Web API is very much the same as in the ASP.NET MVC. The ASP.NET Web API routes URLs to a controller. Then, the control is handed to the action that corresponds to the HTTP verb of the request message. Note that the default route template for an ASP.NET Web API project is {controller}/{id}
—here the {id}
parameter is optional. Also, the ASP.NET Web API route templates may optionally include an {action}
parameter. It should be noted that unlike the ASP.NET MVC, URLs in the ASP.NET Web API cannot contain complex types. It should also be noted that complex types must be present in the HTTP message body, and that there can be one, and only one, complex type in the HTTP message body.
In the ASP.NET Web API framework, the controller handles all HTTP requests. The controller comprises a collection of action methods—an incoming request to the Web API framework, the request is routed to the appropriate action. Now, the framework uses a routing table to determine the action method to be invoked when a request is received.
Here is an example:
routes.MapHttpRoute( name: "Packt Web API", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
Refer to the following UserController
class. Note that it extends the BaseApiController
class we designed earlier in this chapter:
public class UserController <UserAuthentication>: BaseApiController<UserAuthentication> { public void GetAllUsers() { } public IEnumerable<User> GetUserById(int id) { } public HttpResponseMessage DeleteUser(int id){ } }
The following table illustrates the HTTP method and the corresponding URI, Actions, and so on:
HTTP Method |
URI |
Action |
Parameter |
---|---|---|---|
|
api/users |
GetAllUsers |
None |
|
api/users/1 |
GetUserByID |
1 |
|
api/users | ||
|
api/users/3 |
DeleteUser |
3 |
The Web API Framework matches the segments in the URI path to the template. The following steps are performed:
The IHttpControllerSelector.SelectController
method selects the controller, takes an HttpRequestMessage
instance, and returns an HttpControllerDescriptor
. After the controller has been selected, the Web API Framework selects the action by invoking the IHttpActionSelector.SelectAction
method. This method in turn accepts HttpControllerContext
and returns HttpActionDescriptor
. You can also explicitly specify the HTTP method for an action by decorating the action method using the HttpGet
, HttpPut
, HttpPost
, or HttpDelete
attributes. Here is an example:
public class UsersController : ApiController { [HttpGet] public User FindUser(id) {} }
You can also use the AcceptVerbs
attribute to enable HTTP methods other than GET
, PUT
, POST
, and DELETE
. Here is an example:
public class UsersController : ApiController { [AcceptVerbs("GET", "HEAD")] public User FindUser(id) { } }
You can also define route by an action name. Here is an example:
routes.MapHttpRoute( name: "PacktActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );
You can also override the action name by using the ActionName
attribute. The following code snippet illustrates two actions: one that supports GET
and the other that supports POST
:
public class UsersController : ApiController { [HttpGet] [ActionName("Token")] public HttpResponseMessage GetToken(int userId); [HttpPost] [ActionName("Token")] public void AddNewToken(int userId); }
To implement the ASP.NET Web API, you need to create a class that derives from the ApiController
class. Now, the methods defined in the Web API controller map to the corresponding HTTP methods. You should ensure that the actions you would like to implement in your Web API Controller class is prefixed with the correct request type (GET
, POST
, PUT
, and DELETE
).
To create an ASP.NET Web API for our Security
database, follow these steps:
Here is how the HomeController
class looks:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace ASP.NET.MVC.WebAPI.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } } }
Here is how the ValuesController
class looks:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace ASP.NET.MVC.WebAPI.Controllers { public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
Now, when you execute the application, here is how the output looks:
Let's create an entity class named Employee
, and use it in the ValuesController
class. I've kept the Employee
class as simple as possible:
public class Employee { public Int32 ID { get; set; } public String FirstName { get; set; } public String LastName { get; set; } }
We will now create an array of the Employee
class and store some data in it using the constructor. Note that an ASP.NET Web API controller derives from ApiController
. Here is how the updated ValuesController
class looks:
public class ValuesController : ApiController { Employee[] employeeArray = null; public ValuesController() { employeeArray = new Employee[] { new Employee {ID = 1, FirstName = "Joydip", LastName = "Kanjilal"}, new Employee {ID = 2, FirstName = "Steve", LastName = "Smith"}, new Employee {ID = 3, FirstName = "Michael", LastName = "Stevens"} }; } public IEnumerable<Employee> Get() { return employeeArray; } public string GetFullName(int id) { return employeeArray[id].FirstName + " " + employeeArray[id].LastName; } }
Let's now see how the output looks when we execute the application and invoke the Web API.
Now, let's invoke the Web API controller and pass the Employee ID as the parameter. Here is how the output looks like:
We will now design a BaseApiController
class—a class that would serve as base for all controller classes. Here is how the initial version of this class would look:
public class BaseApiController<T> : ApiController where T : class { BaseRepository<SecurityEntities> repository = null; public BaseApiController() { repository = new BaseRepository<SecurityEntities>("SecurityEntities"); } }
Here is how the initial version of the BaseRepository
class looks:
public class BaseRepository<TContext> : IDisposablewhere TContext : DbContext, IObjectContextAdapter, new() { private TContext context; private BaseRepository() { } public BaseRepository(string connectionStringName) { context = new TContext(); context.Database.Connection.ConnectionString = "data source=Joydip;initial catalog=SecurityDB;integrated security=True;"; } }
Here's the complete implementation of the BaseRepository
class:
using System; using System.Linq; using System.Data.Entity; using System.Linq.Expressions; using System.Reflection; using System.Data.Entity.Infrastructure; using System.Data; namespace DataAccess { public class BaseRepository<TContext> : IDisposablewhere TContext : DbContext, IObjectContextAdapter, new() { private TContext dataContext; private BaseRepository() { } public BaseRepository(string connectionStringName) { dataContext = new TContext(); dataContext.Database.Connection.ConnectionString = "datasource=Joydip;initial catalog=SecurityDB;integrated security=True;"; } public virtual Int32 CreateData<T>(T TObject) where T : class { var dbSetInstance = dataContext.Set<T>().Add(TObject); return SaveChanges(); } public virtual Int32 RemoveData<T>(T instance) where T : class { dataContext.Set<T>().Remove(instance); return SaveChanges(); } public virtual Int32 EditData<T>(T instance) where T : class { var dbEntityEntry = dataContext.Entry(instance); dataContext.Set<T>().Attach(instance); dbEntityEntry.State = EntityState.Modified; return SaveChanges(); } private Int32 SaveChanges() { return dataContext.SaveChanges(); } public void Dispose() { if (dataContext != null) { dataContext.Dispose(); dataContext = null; } } } }
Here is how the IBaseApiController
interface looks:
using System; namespace ASP.NET.MVC.WebAPI.Models { /// <summary> /// IBaseApiController interface /// </summary> public interface IBaseApiController : IDisposable { int ID { get; set; } } }
The BaseApiController
class extends the ApiController
class and implements the IBaseApiController
interface:
using System; using System.Collections.Generic; using System.Web.Http; using ASP.NET.MVC.WebAPI.Models; using DataAccess; namespace ASP.NET.MVC.WebAPI.Helpers { public class BaseApiController<T> : ApiController where T : class, IBaseApiController { BaseRepository<SecurityEntities> repository = null; protected string[] includesArray { get; set; } /// <summary> /// Default Contructor that initializes the instance of BaseRepository /// </summary> public BaseApiController() { repository = new BaseRepository<SecurityEntities>("SecurityEntities"); } /// <summary> /// Get method to retrieve entity data based on the generic type supplied /// </summary> /// <returns></returns> public virtual IEnumerable<T> Get() { return repository.GetData<T>(includesArray); } /// <summary> /// Get method to retrieve entity data based on the id of the entity /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual T Get(Int32 id) { return repository.SearchData<T>(t => t.ID == id, includesArray); } /// <summary> /// Post method - edits data /// </summary> /// <param name="value"></param> /// <returns></returns> public virtual Int32 Post([FromBody]T value) { return repository.EditData<T>(value); } /// <summary> /// Put method - creates / inserts new entity /// </summary> /// <param name="value"></param> /// <returns></returns> public virtual Int32 Put([FromBody]T value) { return repository.CreateData<T>(value); } /// <summary> /// Delete method - deletes an existing entity /// </summary> /// <param name="value"></param> /// <returns></returns> public virtual Int32 Delete([FromBody]T value) { return repository.RemoveData<T>(value); } } }
In a standard ASP.NET MVC project, the route configuration is defined in the Global.asx.cs
file. On the contrary, in a standard ASP.NET Web API project you would have a RouteConfig
class and a WebApiConfig
class inside the Application_Start
folder.
Note that the RouteConfig.cs
file is similar to a standard ASP.NET MVC project, and is used to set up routes for the MVC framework. The WebApiConfig.cs
file is actually where the ASP.NET Web API routing configuration is specified. The WebApiConfig
class looks like this:
using System; using System.Collections.Generic; using System.Linq; uswing System.Web.Http; namespace ASP.NET.MVC.WebAPI { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }