ASP.Net WEB API Against WCF

In this article, we will try to understand the concept of the ASP.NET Web API along with examples of creating a WebAPI and consuming it step-by-step. This article is intended for an audience with a basic understanding of WCF and MVC.

So what are the points that we will be covering today?

  1. What is ASP.NET WEBAPI
  2. Why ASP.NET Web API when we already had WCF REST Services
  3. Creating a sample application using Web API
  4. When to use WCF and when Web API

What is ASP.NET Web API?

We know that HTTP is mainly used for serving webpages/images/PDFs. But then Microsoft had changed our idea of looking into this HTTP by making HTTP used for building the strong API that can reach a large number of clients, like browsers, mobile devices and so on in a more flexible way. As we have access to the internet so we access HTTP. Hence HTTP is found everywhere today. So making this HTTP a powerful tool for exposing services to the client is what is called the ASP.NET WEB API.

The ASP.NET WEBAPI is a platform for building HTTP services that can be used over the web, on the top of .Net framework. This framework mainly works on HTTP standard verbs like GET, POST, PUT, DELETE, OPTIONS, and HEAD and uses the REST architecture. Here request for data can be made using a Uniform Resource Interface (URI) that actually can understand these HTTP verbs.

Each method specified above has some specifications. The GET method should be used to get the resources from the server. Likewise the POST method should be used to post the resources to the server.

These resources can be any non-SOAP content like XML, JSON, TEXT, IMAGE and many more.

Wow isn't it? But all this can be done using WCF REST also.

Why ASP.NET Web API when we already had WCF REST Services

WCF is a powerful programming model for creating SOAP based services to support various protocols like Messaging queue, duplex communication, one way messaging, transaction based communication and so on by making small configuration changes. As you know, SOAP allows all settings required for any services in the message itself. Using WebHTTPBinding, WCF can support REST based services. So why was the WEB API brought into the market? The answer is:
  • As explained before, it supports HTTP, an application level protocol. That means indirectly it supports the HTTP standard verbs that define the action (GET, POST, PUT, DELETE and HEAD).
  • It provides strong support for URL routing using MVC style routing.
  • It contains message headers that are self-descriptive. It explains the ContentType of messages, cache information, Content Negotiation based on Accept headers for request and response serialization.
  • It supports non-SOAP output formats like JSON, XML, ATOM and also supports new input/output types
  • It can be self-hosted in non- Web Applications.
  • Also Unit Testing is made easy since it is similar to the MVC Architecture.

    Let's create a simple example to explain the WEB API.

    Here, in the WEB API we extend from the controller called ApiController for HTTP verbs. And for returning views (aspx, cshtml) we need to use the default MVC controller. In our sample we will create a service that returns customer details as a resource.

    Note: Before understanding the WEBAPI, you need to have a basic knowledge of MVC Architecture.
1. To create a WEB API, you need a MVC Template. First of all create a new MVC web application and select the WEB API.

2. As you can see, as a default template we have a controller that extends from ApiController.

This is our API Controller in which we will be writing our Http Methods.



3. Routing



There is 1 more routing config that has been added to the App_Start folder, WebApiConfig.cs along with RouteConfig.cs. This Config file contains a similar Routing table that we usually see in MVC routing. But the only difference we find over here is the routingTemplate starts with api/{controller}/{id} and there is not an action specified. As I said before the WEBAPI mainly works on HTTP verbs which means if I have any action that starts with GET (for example: GetCustomer), it will consider it as a WEBAPI method. The same for the other methods also.


4. Adding a model: A model can be any class that represents the data in your application. The ASP.NET Web API can automatically serialize your model to JSON, XML, or some other format and then write the serialized data into the body of the HTTP response message. So I am creating a Customer Model over here.


  1. public class Customer  
  2. {  
  3.     [Key]  
  4.     public int CustomerId { getset; }  
  5.   
  6.     [Required(ErrorMessage = "Enter Customer Name")]  
  7.     public string CustomerName { getset; }  
  8.   
  9.     [Required(ErrorMessage = "Enter Customer Code")]  
  10.     public string CustomerCode { getset; }  
  11.   
  12.     [Required(ErrorMessage = "Enter Address")]  
  13.     public string CustomerAddress { getset; }  

5. Adding a controller: In the Web API, a controller handles HTTP requests. Let's provide the controller name as CustomerController.

Note: This Controller should inherit the ApiController class instead of Controller class as in MVC.



In the Controller, I am adding the HTTP methods as shown below. I am not writing any database driven code, it will just get the list of Customers from the Cache object and perform an operation on it.

  1. public class CustomerController : ApiController  
  2. {  
  3.     public List<Customer> customers = new List<Customer>() {   
  4.         new Customer{ CustomerId = 1, CustomerCode = "C01", CustomerName = "ABC", CustomerAddress = "Mumbai"  }  
  5.         ,new Customer{ CustomerId = 2, CustomerCode = "C02", CustomerName = "DEF", CustomerAddress = "Delhi"  }  
  6.         ,new Customer{ CustomerId = 3, CustomerCode = "C03", CustomerName = "XYZ", CustomerAddress = "New York"  }  
  7.   
  8.     };  
  9.   
  10.     /*GET Method*/  
  11.     public IEnumerable<Customer> Get()  
  12.     {  
  13.         if (System.Web.HttpContext.Current.Cache["custlist"] == null)  
  14.         {  
  15.             System.Web.HttpContext.Current.Cache["custlist"] = customers;  
  16.         }  
  17.         else  
  18.         {  
  19.             customers = System.Web.HttpContext.Current.Cache["custlist"as List<Customer>;  
  20.         }  
  21.   
  22.         return customers;  
  23.     }  
  24.   
  25.     /*GET method with parameter*/  
  26.     public Customer Get(int id)  
  27.     {  
  28.         if (System.Web.HttpContext.Current.Cache["custlist"] == null)  
  29.         {  
  30.             System.Web.HttpContext.Current.Cache["custlist"] = customers;  
  31.         }  
  32.         else  
  33.         {  
  34.             customers = System.Web.HttpContext.Current.Cache["custlist"as List<Customer>;  
  35.         }  
  36.         return customers.Where(d => d.CustomerId == id).SingleOrDefault();  
  37.     }  
  38.   
  39.     /*POST Method*/  
  40.     public Customer Post(Customer cust)  
  41.     {  
  42.         if (System.Web.HttpContext.Current.Cache["custlist"] == null)  
  43.         {  
  44.             System.Web.HttpContext.Current.Cache["custlist"] = customers;  
  45.         }  
  46.         else  
  47.         {  
  48.             customers = System.Web.HttpContext.Current.Cache["custlist"as List<Customer>;  
  49.         }  
  50.   
  51.         if (cust.CustomerId == 0)  
  52.         {  
  53.             cust.CustomerId = customers.Max(t => t.CustomerId) + 1;  
  54.             customers.Add(cust);  
  55.         }  
  56.         else  
  57.         {  
  58.             Customer c1 = customers.Find(c => c.CustomerId == cust.CustomerId);  
  59.             customers.Remove(c1);  
  60.             customers.Add(cust);  
  61.         }  
  62.         System.Web.HttpContext.Current.Cache["custlist"] = customers;  
  63.         return cust;  
  64.     }  
  65.   
  66.     /*PUT Method*/  
  67.     public Customer Put(Customer cust)  
  68.     {  
  69.         var t = Get(cust.CustomerId);  
  70.   
  71.         if (t == null)  
  72.             throw new Exception(string.Format("Task with id {0} not exists.", cust.CustomerId));  
  73.   
  74.   
  75.         return t;  
  76.     }  
  77.   
  78.     /*DELETE Method*/  
  79.     public bool Delete(int id)  
  80.     {  
  81.         var c = Get(id);  
  82.         if (c == null)  
  83.             return false;  
  84.   
  85.         if (System.Web.HttpContext.Current.Cache["custlist"] == null)  
  86.         {  
  87.             System.Web.HttpContext.Current.Cache["custlist"] = customers;  
  88.         }  
  89.         else  
  90.         {  
  91.             customers = System.Web.HttpContext.Current.Cache["custlist"as List<Customer>;  
  92.         }  
  93.         customers.Remove(c);  
  94.         return true;  
  95.     }  

That's it! Our Web API is ready for action. Now as I told you before it is a resource oriented service, so each method will correspond to one or more URIs.

Controller Method URI
Get api/Customer/
Get(id) api/Customer/id
Post POST api/Customer/
Put PUT api/Customer/
Delete DELETE api/Customer/
 
6. Now let's consume this resources using jQuery. I have designed a simple UI that will have fields to capture Customer Details and the same list be shown below in the grid with edit and delete functionality.



Listing functionality
  1. $('#btnlist').click(function () {  
  2.           $.getJSON('/api/Customer', function (c) {  
  3.               $('#result').html('');  
  4.               var str = '';  
  5.               str+="<table class='mGrid'>";  
  6.               str+='<th>Customer Code</th><th>Customer Name</th><th>Address</th><th></th><th></th>';  
  7.               $(c).each(function (i, item) {  
  8.                   str+='<tr>';  
  9.                   str+='<td>' + item.CustomerCode + '</td>';  
  10.                   str+='<td>' + item.CustomerName + '</td>';  
  11.                   str+='<td>' + item.CustomerAddress + '</td>';  
  12.                   str+='<td>' + '<input type="button" id="editbtn" value="Edit" onclick="fnEdit(' + item.CustomerId + ');"/></td>';  
  13.                   str+='<td>' + '<input type="button" id="delbtn" value="Delete" onclick="fnDelete(' + item.CustomerId + ');"/></td>';  
  14.                   str+='</tr>';  
  15.               });  
  16.               str+="</table>";  
  17.               $('#result').html(str);  
  18.           });  
  19.       }); 

Save functionality

  1. $('#btnsave').click(function () {  
  2.          var CId = $('#CustomerId').val();  
  3.          var CCode = $('#CustomerCode').val();  
  4.          var CName = $('#CustomerName').val();  
  5.          var CAddress = $('#CustomerAddress').val();  
  6.          var C = { CustomerCode: CCode, CustomerName: CName, CustomerAddress: CAddress,CustomerID: CId };  
  7.          $.post("@Url.Content("/api/Customer/")", C).done  
  8.          (  
  9.              function (msg) {  
  10.                  $('#btnlist').click();  
  11.                  alert("Updated Sucessfully");  
  12.                  $('input:not([type=button])').val('');  
  13.              }  
  14.   
  15.         ).fail(function (e) { alert(e.statusCode);});  
  16.      }); 

Edit Functionality

  1. function fnEdit(cid) {  
  2.             var C = { CustomerId: cid };  
  3.             $.ajax(  
  4.                 {  
  5.                     url: "@Url.Content("/api/Customer/")"  
  6.                     , type: "PUT"  
  7.                     , datatype: 'json'  
  8.                     , data: C  
  9.                     , success: function (msg) {  
  10.                         if (msg != null) {  
  11.                             $('#CustomerCode').val(msg.CustomerCode);  
  12.                             $('#CustomerName').val(msg.CustomerName);  
  13.                             $('#CustomerAddress').val(msg.CustomerAddress);  
  14.                             $('#CustomerId').val(msg.CustomerId);  
  15.                         }  
  16.                     }  
  17.   
  18.                 });  
  19.         } 

Delete Functionality



As you can see above, I have passed the header as a parameter to the ajax method. Because the DELETE method was not being called by passing the type :DELETE. This is due to the browser or firewall.

How to overcome that

One thing we can do is the override the HTTP methods inside with other supported HTTP methods.
It means call the HTTP service with the POST method but when routing call the override with other methods, say DELETE as header as shown below.

X-HTTP-Method-Override:DELETE"

To do this you need to write one MethodOverrideHandler and register it in MessagingHandler:



Register this method

config.MessageHandlers.Add(new MethodOverrideHandler());

When to use WCF and when Web API

  1. If you want to expose a service to the public and the same service you want to work on various protocols like Messaging Queue, TCP, Named Pipes or duplex communication go for WCF.
  2. If you want to create a service that supports HTTP and SOAP-based messaging, go for WCF.
  3. If you want to create a resource-oriented service over HTTP and use the full features of the HTTP protocol then go for the ASP.NET WEBAPI.
  4. If you want to access services based on URI and get a non-SOAP response like XML or JSON then go for ASP.NET WEBAPI.
  5. If you have an application developed in MVC and want to have a service to be exposed then go for the WEBAPI. Automated Testing of business logic will also be easy for services since controller is separated from the UI and Model.

Conclusion

The Web APIs, therefore, were intended to allow creating HTTP services that only use the standard HTTP concepts (URIs and verbs) and use more advanced HTTP features like request/response headers, caching information and so on. I hope you will like this article. Don't forget to share your comments whether it's good or bad. Sharing is valuable no matter what.

References

Tiny Happy Features #2 - ASP.NET Web API in Visual Studio 2012