Working with the ASP.NET Web API

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.

Working with the ASP.NET Web API

Layers of an application

The ASP.NET Framework runs on top of the managed environment of the .NET Framework.

Working with the ASP.NET Web API

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:

Working with the ASP.NET Web API

The MVC architecture

The ASP.NET Web API 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

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.

Note

Note that the ASP.NET MVC and the ASP.NET Web API are two distinctly separate frameworks which adhere to some common architectural patterns.

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

GET

api/users

GetAllUsers

None

GET

api/users/1

GetUserByID

1

POST

api/users

  

DELETE

api/users/3

DeleteUser

3

The Web API Framework matches the segments in the URI path to the template. The following steps are performed:

  1. The URI is matched to a route template.
  2. The respective controller is selected.
  3. The respective action is selected.

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);
}

Implementing the ASP.NET Web API for the Security database

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:

  1. Right-click on the solution explorer window.
  2. Select Add New Project.
    Implementing the ASP.NET Web API for the Security database

    Creating a new ASP.NET Web API project

  3. Select ASP.NET MVC 4 Web Application from the list of the templates under the Web category as shown in the previous figure.
  4. Specify a name for the project, and click on OK.
  5. Select Web API as the Project Template, as shown in the following screenshot:
    Implementing the ASP.NET Web API for the Security database

    Selecting the project template

  6. Ensure that View engine selected is Razor. Click on OK when done.

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:

Implementing the ASP.NET Web API for the Security database

The output in the web browser

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.

Implementing the ASP.NET Web API for the Security database

The ValuesController class in execution

Now, let's invoke the Web API controller and pass the Employee ID as the parameter. Here is how the output looks like:

Implementing the ASP.NET Web API for the Security database

Retrieving a particular record

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.

Implementing the ASP.NET Web API for the Security database

RouteConfig and WebApiConfig in ASP.NET Web API

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 }
            );
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset