Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET MVC5 Features - WebAPI 2

0.00/5 (No votes)
10 Aug 2014 1  
This article explains WebAPI v2 features of ASP.NET MVC5

Introduction

ASP.NET MVC5 comes with version 2 of the WebAPI. For those of you who are new to WebAPI, its a new RESTful service provided by ASP.NET where we can implement our own REST based service using HTTP verbs GET, POST, PUT, DELETE etc and use JSON or XML for data transport. Microsoft also has another REST service offering using WCF REST.

For those new to REST services, its a flavour of service embracing the Web using HTTP without any toolkit(which SOAP services generally use). For more details on REST, please go through http://en.wikipedia.org/wiki/Representational_state_transfer. 

Background

This is my 2nd article in the ASP.NET MVC5 series. Here I'll try to explain WebAPI from the ground up so even if you don't have prior knowledge in Web API version1, that should be fine.

Lets get started with exploring WebAPI

Create a new ASP.NET project and select the Web API template.

If you want, you can change the Authentication types to one of the more suitable ones to you, but I'll keep "No Authentication" and let it open for anonymous users.

If you try running the project without changing the project, you would be able to see a Home Page. If you click on the API menu at the top, you will see a API help page with some documentation. I'll come back to explain the workings on this help page later. But for now, just try browsing what the api help page shows as one of the URI's GET api/Values with http://localhost:14129/api/Values and you will see some values in XML format.

So this means our WebAPI is up and running and serving data back to us.

Lets have a look at the code in the solution project. If you open up the controllers folder, you will see a HomeController which is a normal ASP.NET MVC controller (so inheriting from the Controller class). This controller returns the Home view that we saw earlier. The 2nd controller named ValuesController is a WebAPI controller (look it inherits from ApiController). If you have a look at the methods, those are methods basically used for doing CRUD operations.

Lets see which method does which operation for CRUD (http://en.wikipedia.org/wiki/Create,_read,_update_and_delete).

1. Get methods to retrive data

There are 2 Get() methods one returning a collection and one returning a particular value(to which a parameter is also supplied). This is the Read in CRUD and uses the HTTP verb GET.

Typically you will retrive data from a data source like a Database.

2. Post method to create record

The Post method will be supplied with data posted typically from a Form in a web page(not necessary though and it may be POSTed by other ways too) and is used to create a record in a data store.

This is the Create in CRUD and uses HTTP verb POST.

3. Put method to update record

The Put method will be supplied with a id parameter and value parameter(typically in object form) and is used to update a record whose id is supplied.

This is the Update in CRUD and uses HTTP verb PUT.

4. Delete method to delete record

The Delete method will be supplied with a id parameter and is used to delete a record from a data store.

This is the Delete in CRUD and uses HTTP verb DELETE.

Now lets try to create our own ApiController to do some more complex operations and name it DepartmentController.

We'll select an Empty controller template.

To keep things simple, we will use a static collection of Departments and Employees using an IEnumerable. In practical applications, we will get/store this data in some database. We will add some model classes in our project.

    public class Department
    {
        public int ID { get; set; }
        public string DepartmentName { get; set; }
        public ICollection<Employee> Employees { get; set; }
    }
    public class Employee
    {
        public int ID { get; set; }
        public string EmployeeName { get; set; }
    }

So lets create some dummy data in our DepartmentController constructor.

public class DepartmentController : ApiController
    {
        public static List<Department> departments;
        public DepartmentController()
        {
            departments = new List<Department>() { 
                new Department{ ID = 1, 
                                DepartmentName = "Computer Science",
                                Employees = new List<Employee>{
                                                new Employee{ ID = 1, EmployeeName = "Robert Scott"},
                                                new Employee{ ID = 2, EmployeeName = "Martin Scale"}
                                                            }
                },
                new Department{ ID = 2, 
                                DepartmentName = "Mechanical",
                                Employees = new List<Employee>{
                                                new Employee{ ID = 3, EmployeeName = "Indiana Twain"},
                                                new Employee{ ID = 4, EmployeeName = "Tom Spain"}
                                                            }
                }
            };
        }
    }

Now lets write our first Get method to GET the list of deparments.

public IEnumerable<Department> Get()
{
     return departments;
}

Now we try to do a GET request using our browser to http://localhost:14129/api/Department and we get the collection of departments back in XML.

If you are new to Web API, you might be thinking that we never called the Get() action method then how did we get the departments back. Yes thats a bit of magic that ASP.NET Web API does it for us with the default routing configuration. So any method name that begins with a Get will be mapped when a HTTP GET request is received. It just has to match the parameters and there should be just one action with the same method signature else Web API throws an InvalidOperationException.

Lets have a look at the default routes in the WebApiConfig class in the folder App_Start.

public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Attribute based routing
            config.MapHttpAttributeRoutes();

            //Default web api route
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

Web API 2 comes with Attribute routing and this line of code below enables attribute based routes. See that it is placed before the default Web API route so that we have a choice to do attribute based routing.

config.MapHttpAttributeRoutes();

Lets try to add another Get method which takes an id as parameter and returns a Department.

public Department GetDepartmentByID(int id)
{
     return departments.FirstOrDefault(x => x.ID == id);
}

Lets try to do a GET request to the browser to the above api method http://localhost:14129/api/Department/1

and we get back the XML data back for the particular department 1.

Now if we look at our data of Departments and Employees, every Department has an Employees collection inside it. With just our default route in place lets try to retrive the Employees collection for a particular department.

E.g. http://localhost:14129/api/Department/1/Employees and we get an HTTP 404 which means the resource is not found. Ok so the default route doesn't handle this case because it just has a map route which takes the routeTemplate: "api/{controller}/{id}". We could have added another route and could have solved our problem.

However with Attribute based routing its much easier and our WebApiConfig also remains clean.

We will add another api method and decorate it with attributes.

        [Route("api/department/{id}/employees")]
        public IEnumerable<Employee> GetEmployeesByDepartmentID(int id)
        {
            return departments.FirstOrDefault(x => x.ID == id).Employees;
        }

Now when we try to run http://localhost:14129/api/Department/1/Employees, we get the employee collection data back. So with attribute based routing we can add api methods as per our needs just by decorating with C# attributes.

Lets try to add some more rules to the above attribute route

[Route("api/department/{id:int:min(1):max(2):maxlength(1)}/employees")] 

So here we are saying that the id should be an int, min value should be 1, max value should be 2 and maxlength should be 1. So we can add as many rules to our attribute as per our needs.

We can add multiple routes per method, can apply to the entire controller and not to forget these rules work in normal MVC controllers too.

I am providing an exhaustive list of rules below from this link http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)} 
{x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

CORS Support(Cross Origin Resource sharing)

CORS means making a request from the browser from one domain usually in Javascript  to another domain and get the response back. Usually browsers disallow doing this because of security issues. However if the originating domain sends to the origin information in the CORS call to the other domain and that domain has agreed to send the response back then it sends an HTTP header information Access-Control-Allow-Origin setting the value of the source origin and sends the response back. In this case, the browser successfully gets the response back.

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing

In the previous version of Web API, we had to do certain configurations and add some file to make this work. This article explains some way to implement CORS in Web API 1 http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/21/implementing-cors-support-in-asp-net-web-apis-take-2.aspx

Now lets see how we can do it in Web API2.

1. Install the nuget package Microsoft.AspNet.WebApi.Cors

2. Configure Web API to enable CORS support.

- At a global level we can do it in the WebApiConfig file

 public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            //Enable CORS support
            config.EnableCors(new EnableCorsAttribute("http://localhost:9001", "*", "GET,POST,PUT"));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

The parameters it takes are origin, headers and the http verbs.

- We can also configure CORS at a controller level by using attribute.

[EnableCors("http://localhost:9001", "*", "GET,POST")]
    public class DepartmentController : ApiController{}

To test CORS support now, create another website with different port and make an AJAX call to the above DepartmentController and you would be able to get the data back. 

IHttpActionResult

Let me introduce you to one more feature of Web API 2. This version of Web API brings in a new interface IHttpActionResult which is used to return an HTTP response message. Yes it sounds similar to MVC ActionResult and in a way it is similar.

E.g implementations are ConflictResult, OkResult, NotFoundResult etc. You will find many in the snapshot below.

 

Lets try modifying one of our API method using IHttpActionResult.

        public IHttpActionResult GetDepartmentByID(int id)
        {
            var department = departments.FirstOrDefault(x => x.ID == id);
            if(department == null)
            {
                //Return not found result
                return NotFound();
            }
            //Return successful ok result
            return Ok(department);
        }

So you can see how easy it is to return appropriate HTTP response messages like NotFound or Ok if we use the IHttpActionResult interface. Not to mention as we are using an interface so unit testing becomes easier too.

 

Help Page documentation

In the beginning I told you something about the API help page. Now lets see how it works.

Once we are on the home page of our sample web api solution and we click on the API menu on the top http://localhost:14129/Help we are taken to a page where we see some listing and documentation of the ApiControllers present in the project.

There is a nuget package, Microsoft.AspNet.WebApi.HelpPage which does this magic behind the scenes.The content of this nuget package resides in the HelpPage Areas in our webapi project.

 To add description information to our documentation, we have to do the following.

1st is in the project build properties, check XML documentation file.

2nd is just add XML comments to our API methods.

        /// <summary>
        /// Gets the department collection.
        /// </summary>
        /// <returns>Department collection</returns>
        public IEnumerable<Department> Get()
        {
            return departments;
        }

3rd - In the HelpPageConfig class in the App_Start folder of HelpPage Areas, uncomment the first line. Also set the XML file path appropriately as shown below.

 public static void Register(HttpConfiguration config)
        {
            //// Uncomment the following to use the documentation from XML documentation file.
            config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/SampleWebAPIv2.XML")));

Now run the project and go to the API menu and we can see the documentation we added.

 

History

This is a continuation of my ASP.NET MVC 5 features series of articles.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here