Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / Azure

Web API and Windows Azure. Part 1. History, a bit about REST, examples.

5.00/5 (2 votes)
25 Jun 2013CPOL16 min read 30.4K  
This series will be about Web API and its use in Windows Azure

In this part:

  • History
  • What is the use of Web API, if there is, for instance, WCF
  • REST Concepts and RMM Model
  • The first application example of ASP.NET MVC + Web API + jQuery + AJAX
  • Using OData in Web API

So, to understand the use of this all, we need to make the subject and its purpose clear. But let’s begin with some history to clarify (from my point of view) the need for Web API introduction.

History

Without falling too far into past details, it would be best to mention that Microsoft had a long way of developing service-oriented systems that has the main pillars: ASMX, .NET Remoting, WCF. Using web services based on ASMX (approx. in 2002), developers could quiet easily create a web service that implemented various versions of SOAP, but it was accessible only over HTTP. At the same time, there was Remoting technology that enabled service developing not only using HTTP. In 2006 Microsoft released .NET 3.0 and Windows Communication Foundation (WCF) that covered both ASMX and .NET Remoting offerings, and suggested even more interesting opportunities. For example, it’s easy to develop a web service for TCP with the help of WCF, with token-based authentication, and run it in “with-Windows-own-hand” developed service. I personally got acquainted with WCF in 2009, when I developed program infrastructure for collecting logs for a couple dozens of machines – there were WCF-service running at headnode machine, and the rest machines performed Powershell script once per N minutes that called WCF-service and sent it the data. I would not claim that it’s easy to perform for the first time, but I appreciated the elegancy of the approach.

In 2007 ASP.NET MVC framework was released in CTP version. Even then the idea was hovering in the air: the Internet is used quite easily – the process of web-page information exchange mostly uses text messages instead of binary data, HTTP is used, client part for various tasks handling. That lead to the idea of developing something that would have serialization backup only in XML and JSON. What for would I use, in particular, that was a partially heavy WCF that eventually did not utilize REST from the beginning, if I wanted to create the simplest RESTful service? So here came ASP.NET MVC with its built-in routing mechanism.

MVC Routing

As opposed to WCF, where service is equal to physical file path, MVC Routing mechanisms work differently: it associates an address with the address of a controller’s method. E.g., if we used WCF, then call to the service would be:

http://server/MyService.svc

And if we used ASP.NET MVC:

http://server/MyService/Get/123

As you can see, such addressing enables you to encapsulate internal behaviour. MVC routing also enables you to transfer a request from the address mentioned above to arbitrary controller methods . This all brings to a much easier further application support: we can alter internal behaviour in the way that is convenient, e.g., quickly change an old implementation for a new one just having touched up the routing configuration. With the help of such routing mechanism, Web API creation (actually, additional layer on ASP.NET) enabled developing HTTP REST-services that work for the same project with ASP.NET MVC, and can be entirely integrated into MVC pipeline (into the logical one, not into implementation). But before you start to write REST-service with Web API, we need to clarify what is meant by REST-service – coming further.

A bit about RET

Some say that to make links nice means to make 100% REST compliant API. Indeed, it’s not true, and REST (was mentioned for the first time in a dissertation of one of the one intelligent fellow), is not as simple as it seems to be. Construction rules for REST-services refer to some limits that also define the architecture, so, you would have to take that into consideration, and either agree or disagree with it.

To understand the core of REST, we will use RMM (REST Maturity Model) that was introduced by Leonardo Richardson in 2008. Those who are familiar with CMMI (Capability Maturity Model Integration) will immediately notice word similarity – and it’s not by accident. Like CMMI, this model describes several levels of compliance with some set of rules and methodology. RMM implies 4 levels – from 0 to 3. In this model, everything starts with the simplest things at Level 0, where API corresponds to RPC style, and everything ends with a conformity to all the basic paradigms - REST. Surely, if you use this system to describe your own model and get stuck at some level that is lower than 3 – your service is not REST. Let’s look at a not-very-artistic RMM picture, and then study an example of guestbook service in accordance with RMM.


Level 0

According to Level 0, we would just have a WCF-service GuestService that had one method CreatePost() that would receive such arguments as record’s heading, user’s name and e-mail. The method would return the record’s number. For the administrator there would be some more methods – DeletePost() and UpdatePost(). Each of them would receive some message and return some answer. And, of course, GetAllPosts(). A simple system.

So, our service at Level 0 RMM would look like that:

Method

URL

HTTP verb

Visibility

CreatePost

/api/GuestService.svc

POST

e.g., WSDL

DeletePost

/api/GuestService.svc

POST

e.g., WSDL

UpdatePost

/api/GuestService.svc

POST

e.g., WSDL

GetAllPosts

/api/GuestService.svc

POST

e.g., WSDL

According to the table, we would have some API with all the operations having their own links (URLs). Yet, links look entirely inexplicit and unrelated to the semantic context: whether we delete a record #1 or update a record #100 – URL would remain the same. Such system corresponds to Level 0 of RMM and to its main characterictic: one URL = one HTTP verb. HTTP verbs give the same results: POST for everything, moreover, you would have to write your own methods. One of RESTful HTTP’s rules is no need for new methods creation: just conform to the list that includes all the necessary HTTP verbs. We will talk about them a bit later.

Surely, it is worth to take into account that the client (in this situation with the service) has to know how to call needed operation, that is, are there any logical connections such as contracts (here we go with WSDL). But do we actually need extra logical connections? Even REST requires us to know only the base URL, and all other operations should be accessible at so-called hypermedia elements (links, forms, etc). The server should control the whole process and dictate the appearance of links and forms without sharing this information with a client, so that it can react properly if any changes occur in the system. These are all HATEOAS principles, coming up later. So, let’s move to Level 1.

Level 1

So, we decided to make our service a REST one. What steps should we take? First, our service should conform to Level 1, that is, a REST-service should be resource-oriented: using not request-response pattern and methods like in RPC, but resources accessible via HTTP vverbs – and that’s it. GET, DELETE, POST, sometimes PUT, and HEAD from time to time. This principle is fundamental for REST-services: if your service offers a bunch of various methods, it would not be a REST one (according to RMM).

Thereby, following Level 1 rule “Arbitrary URL = one HTTP verb”, let’s create a new table for API.

Method

URL

HTTP verb

Visibility

CreatePost

/api/posts

POST

e.g., WSDL

DeletePost

/api/posts/1

POST

e.g., WSDL

UpdatePost

/api/posts/1

POST

e.g., WSDL

GetAllPosts

/api/posts

POST

e.g., WSDL

But here we have a RESTful-ness problem: a client still does not comprehend how the links differ without service contract: /api/posts and /api/posts and, for instance, WSDL. A client should have a contract. Level of cohesion remains the same, and apart from this, one HTTP verb is still observed. At least our service reached Level 1 of RMM. Let’s try to move on to Level 2.

Level 2

Level 2 rule is “Arbitrary URL = Arbitrary HTTP verbs”. This is when we have to reconsider our service as resource-oriented. What’s coming from a client? How to process it? Where to send it?

As a matter of fact, such HTTP verbs as CreatePost and GetAllPosts do not exist. But there are POST, GET, PUT, and DELETE so we can utilize them and move on to Level 2. Note that HTTP verbs have some features, e.g., PUT and DELETE are idempotent. That is, whenever we call on them, they would return the same result as HTTP-answer: e.g., regardless of when we call for PUT, it would change the same entity. POST is not idempotent for a known reason: a new entity is created. GET is not idempotent, but it’s safe – there are no changes in the system and it must be that way whenever we call on GET. It’s really important, I saw a system in which GET-method showed on the server side logical changes in entities states in the data source – and that’s not right.

So let’s look at our service at Level 2.

Method

URL

HTTP verb

Visibility

CreatePost

/api/posts

POST

e.g., WSDL

DeletePost

/api/posts/1

DELETE

e.g., WSDL

UpdatePost

/api/posts/1

PUT

e.g., WSDL

GetPost

/api/posts

GET

e.g., WSDL

Looks much better. Now we have a service corresponding to HTTP verbs and various URL (mostly). But we remain cohesive to a client. To resolve this we move on to Level 3.

Level 3

Level 3 is HATEOAS. The message in this abbreviation is for a client to know nothing but the initial site address. The remaining information will be given to a client with the help of links, buttons, other semantic elements. A client should get an access to the resources and their state without any primary knowledge how to do it.

So, an API corresponding to Level 3 is provided in the table. Note, that even if a service corresponds to all RMM features, there may be some nuances crashing everything down.

Method

URL

HTTP verbs

Visibility

CreatePost

/api/posts

POST

HTTP POST

DeletePost

/api/posts/1

DELETE

HTTP DELETE

UpdatePost

/api/posts/1

PUT

HTTP PUT

GetPost

/api/posts

GET

HTTP GET

The last words about REST

And a few last words about REST: it’s important to remember about standard HTTP error codes so that your service would conform to REST. A service should return known error codes. Such terms are not to be necessarily followed, but their creation and usage was approved by the smartest people, and would help those who support the service understand that the author of the code was not inadequate while creating the service.

Code status

Meaning

200

ОК.

201

Entity was created so response could include a link to a newly created entity

202

The same as 200, but it is used with async operations.

301

Resource was moved. Response could include link to a new resource.

400

Bad request (client-side).

401

Unauthorized.

403

Access is forbidden – client was authenticated but not authorized.

404

Resource was not found or client don’t have an access to it and should not know why.

409

Server error.

500

Server error.

Web API

Recall that Web API appeared in ASP.NET MVC 4 and provoked lots of discussions: another technology helping to create a web-site, and again REST – what for? That’s a good question – when there are various technologies like WCF among many other. But these are all “global” things, and when it comes to some big app implementation, you would have to drag a bit of not-so-surely-useful tools “just-in-case” they help. Web API is the tool which enables in an easy, quick, and nice implementation of RESTful-service using HTTP.

Let’s create ASP.NET MVC 4 application and choose a corresponding Web API template.

After a project creation, you will see a MVC-application. The first entry point would be a specialized WebAPI ValuesController that is by-turn inherited not from Controller, but from ApiController.

Just like in any controller, scaffolding creates a code: in case of Web API-controller it’s stubs for the HTTP verbs methods: GET, POST, PUT, and DELETE.

HTTP Verb

Controller method

Description

Get()

GET

Method returns an array of data of any Ienumerable-related type.

Get(string)

GET

Method returns one entity based on method argument.

Post(string)

POST

Method adds a new entity.

Put(string,string)

PUT

Method updates existed entity. Difference between Put and Post is that Post always creating a new entity.

Delete(string)

DELETE

Method deletes an entity from a system.

Let’s add a context to a test database. In this article series, I will use a test database that I always use when I teach courses at http://atraining.ru. It consists of two very simple not related to each other tables: CourseSet and Student.

Let’s make some changes in WebAPI controller and correspondingly define its methods. As the code is simple enough, I provide no comments to it.

C#
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Net.Http.Formatting; 
using System.Net.Http.Headers; 
using System.Web.Http; 
using WebApiJsonAjax.Models; 
namespace WebApiJsonAjax.Controllers 
{ 
    public class ValuesController : ApiController 
    { 
        private atrainingdatabaseEntities
_ctx = new atrainingdatabaseEntities(); 
        // GET api/values 
        public List<Models.Student>
Get() 
        {  
             
             
var students = from e in _ctx.Student select e; 
             
return students.ToList();  
      
              
        }
       
        // GET api/values/5 
        public string Get(int id) 
        { 
            return
"value" + id; 
        }
       
public Student Post(Student student) 
        { 
            return
student; 
        }
       
// PUT api/values/5 
        public void Put(int id,
[FromBody]string value) 
        { 
        }
       
// DELETE api/values/5 
        public void Delete(int id) 
        {  
            var student
= _ctx.Student.Where(s => s.id == id).FirstOrDefault(); 
_ctx.Student.Remove(student); 
_ctx.SaveChanges();  
             
        } 
    } 
}

We save the controller and test it: push F5 and follow http://localhost:[port]/api/values. Note that when someone invokes this link using GET verb, he would get a when someone invokes this link using GET verb, he would get a JSON result. WebAPI can process and return values in JSON and XML: it depends on a client’s configuration. Let’s look at what what Chrome and IE return in this case (screenshots are placed correspondingly) to look at another are placed correspondingly) to look at another Web API feature - Content Negotiation.

The whole serialization process of Student-type objects in JSON is performed by a framework (which is really convenient), in comparison to ASP.NET MVC: if we want to return JSON from a controller, we have to use return Json explicitly. Let’s discuss why the results returned by the service in the two browsers are of different formats.

Content Negotiation

Content Negotiation in HTTP standards is a process of communication details negotiation between a client and a server. When a client calls a server, he sends a query with Accept directive pointing out what answer is expected. Let’s perform GET, but with a help of “curl” utility to trace the process. Fiddler screenshots are provided. Moreover, we’ll have a look at queries of Chrome and IE with a help of in-browser integrated applications.

Fiddler interface working in parallel to curl.

Accept value is what a client wants to receive from a server. As we see from the screenshots, Chrome wants to “see” text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 (q is a format “weight”: the bigger the weight, the more wish there is from a client to see the result in a certain format, and tells it to a server). Yet, IE wants to see text/html, application/xhtml+xml, */*. Note that Web API don’t recognize what IE wants to see, and sends the default result to JSON that doesn’t have any support of application/xhtml+xml, but there is */* support, that is “I will receive a content in any type that will be returned by a server”. Chrome receives what it wants in the desirable XML format.

Let’s have a look at the way curl and Fiddler do this.

JSON answer for a client doesn’t care about the result format.

Let’s point out what we would like to see explicitly.

As splendid as it is: the result format depends on a client’s demands.

It is this process that is called Content Negotiation, and it is a very important client-server communication process. Note how easy and elegant the format resolution was. Indication of the result format brings us to a more complicated code provided below.

C#
 public
HttpResponseMessage Get() 
{
   
var students = (from e in _ctx.Student select e);
   
var resp = new HttpResponseMessage(HttpStatusCode.OK); 
    resp.Content = new
ObjectContent<IEnumerable<Student>>(students, new
JsonMediaTypeFormatter());
   
resp.Headers.ConnectionClose = true; 
    resp.Headers.CacheControl = new CacheControlHeaderValue(); 
    resp.Headers.CacheControl.Public = true;
   
return resp;
}
If you want to return the result in the format that is independent from a client’s preferences, you have to get an access to a message that would be formed for the result, and define its properties with a help of a special mechanism – Formatter. It goes without saying that you can create your own converters with a more perplexed logical structure.

So, in the code provided above:

  1. We receive Student collection
  2. An instance of HttpResponseMessage class with a 201 OK status is created. This message will be returned to the client.
  3. The message includes our data model that is converted into JSON format.
  4. The message is returned to a client.

Let’s repeat our query in curl, telling that we want to see only application/xml.

Despite Accept: application/xml, the result was returned in JSON format.

Content Negotiation in Web API in its beauty. We move on.

Using Web API from MVC view with jQuery

So, our REST-service is almost complete. Web API quite naturally does not support any view generation mechanism. Let’s connect our service with MVC view.

We will use Web API from Index view from HomeController. jQuery will take the data from a service and we will create a new table.

The whole page code is provided.

JavaScript
 <header>
    <div class="content-wrapper"> 
        <div
class="float-left"> 
            <p
class="site-title"> 
               
<a href="~/">ASP.NET Web API</a></p> 
        </div> 
    </div> 
</header> 
<div id="body"> 
    <section class="featured"> 
        <div
class="content-wrapper"> 
            
            <table
id="students"></table> 
           
<script> 
               
               
$(function () { 
                   
var $students = $("#students"); 
                   
$.ajax({ 
                       
url: "api/values", 
                       
contentType: "json", 
                       
success: function(data) { 
                           
$.each(data, function(index, item) { 
        var $row =
$("#templates").find(".row-template").clone(); 
       
$row.find(".Name").html(item.name); 
       
$row.find(".delete").click(function() {
       
$.ajax({ url: "api/values/" + item.id, 
                                       
type: "DELETE", 
                                       
success: function() { 
                                           
$row.remove(); 
                                       
} 
                                   
});
                               
}); 
                               
$students.append($row); 
                               
                           
}); 
                       
} 
                   
}); 
               
})
           
</script> 
        </div> 
    </section> 
    <section class="content-wrapper main-content
clear-fix"> 
        
        <div id="templates"
style="display:none"> 
            
           
<table> 
               
               
<tr class="row-template"> 
                   
                   
<td class="Name"></td> 
                   
<td><input type="button" value ="Del"
class="delete"/></td>
               
</tr>
           
</table>
       
</div>
   
</section> 
</div> 

The code is quite simple: we get data from the server and create a dynamic table.

To delete one record means to push an attached button.

Let’s add the remaining functionality: PUT and POST, this will require a lot of code. I provide entire view and controller listings.

 using
System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Net.Http.Formatting; 
using System.Net.Http.Headers; 
using System.Web.Http; 
using WebApiJsonAjax.Models; 
namespace WebApiJsonAjax.Controllers 
{ 
    public class ValuesController : ApiController 
    { 
        private atrainingdatabaseEntities
_ctx = new atrainingdatabaseEntities(); 
       
public HttpResponseMessage Get() 
        {
           
var students = (from e in _ctx.Student select e);
           
var resp = new HttpResponseMessage(HttpStatusCode.OK); 
            resp.Content
= new ObjectContent<IEnumerable<Student>>(students, new
JsonMediaTypeFormatter());
           
resp.Headers.ConnectionClose = true; 
           
resp.Headers.CacheControl = new CacheControlHeaderValue(); 
           
resp.Headers.CacheControl.Public = true;
           
return resp;
       
}
       
// GET api/values/5 
        public string Get(int id) 
        { 
            return
"value" + id; 
        }
       
public HttpResponseMessage
Post([FromBody]Student student) 
        { 
            try 
            { 
               
_ctx.Student.Add(student); 
               
_ctx.SaveChanges(); 
            } 
            catch
(Exception e) 
            { 
               
return Query.CreateErrorResponse(HttpStatusCode.InternalServerError,
e.Message);
        { 
            try 
            { 
               
_ctx.Student.Add(student); 
               
_ctx.SaveChanges(); 
            } 
            catch
(Exception e) 
            { 
               
return Query.CreateErrorResponse(HttpStatusCode.InternalServerError,
e.Message);
           
}; 
            return Query.CreateResponse(HttpStatusCode.OK);
        }
       
// PUT api/values/5 
        public HttpResponseMessage Put(int
id, Student student) 
        { 
            try 
            { 
               
var studentToChange = _ctx.Student.FirstOrDefault(s => s.id == id); 
               
studentToChange.name = student.name; 
               
_ctx.SaveChanges(); 
            } catch
(Exception e) 
            { 
               
return Query.CreateErrorResponse(HttpStatusCode.InternalServerError,
e.Message);
           
}; 
            return Query.CreateResponse(HttpStatusCode.OK);
        }
       
// DELETE api/values/5 
        public void Delete(int id) 
        {  
             
               
var student = _ctx.Student.Where(s => s.id == id).FirstOrDefault(); 
               
_ctx.Student.Remove(student); 
               
_ctx.SaveChanges();  
             
        } 
    } 
} 

PUT and POST method implementations appeared in the controller. Operations in both methods are enclosed in try/catch block, and a message is created and sent if something goes wrong. Note, that there is a very useful attribute: you can mark controller method argument as [FromBody] or [FromUrl], which correspondingly mean to take an argument from the query body or from URL.

View code is provided below. Handlers of record creation and edit events were added. Note that JSON.stringify converts everything given into JSON.

JavaScript
 <header>

    <div class="content-wrapper"> 
        <div
class="float-left"> 
            <p
class="site-title"> 
               
<a href="~/">ASP.NET Web API</a></p> 
        </div> 
    </div> 
</header> 
<div id="body"> 
    <section class="featured"> 
        <div
class="content-wrapper"> 
            
            <table
id="students"></table> 
           
<script>
               
$(function() { 
                   
var $students = $("#students"); 
                   
$.ajax({ 
                       
url: "api/values", 
                       
contentType: "json", 
                       
success: function(data) { 
                           
$.each(data, function(index, item) { 
                               
var $row = $("#templates").find(".row-template").clone(); 
                               
$row.find(".Name").html("<input type=’text’ class=’studentname’
id=’" + item.id + "’ value=’" + item.name +
"’></input>"); 
                               
$row.find(".delete").click(function() {
                                   
$.ajax({ 
                                       
url: "api/values/" + item.id, 
                                       
type: "DELETE", 
                                       
success: function() { 
                                           
$row.remove(); 
                                       
} 
                                   
});
                               
});
                    
          
$row.find(".change").click(function() { 

                                   
var student = { 

                                       
id: item.id, 

                                       
name: $row.find(".studentname").attr("value") 

                                   
};
                                   
var student = { 
                                       
id: item.id, 
                                       
name: $row.find(".studentname").attr("value") 
                                   
};
                      
            
$.ajax({ 

                                       
url: "api/values/" + item.id, 

                                       
type: "PUT", 

                                       
contentType: "application/json; charset=utf-8", 

                                       
data: JSON.stringify(student), 

                                       
success: function() {
                                       
url: "api/values/" + item.id, 
                                       
type: "PUT", 
                                       
contentType: "application/json; charset=utf-8", 
                                       
data: JSON.stringify(student), 
                                       
success: function() {
                                       
} 
                                   
});
                               
});
                               
$students.append($row);
                           
}); 
                       
} 
                   
}); 
               
});
              
function addStudent()
{                   


                   

                   
                   
var student = { 
                      
name: $("#frm").find("#name").attr("value"), 
                   
}; 
                  
$.ajax({ 
                       
url: "api/values", 
                       
type: "POST", 
                       
contentType: "application/json; charset=utf-8", 
                       
data: JSON.stringify(student), 
                       
success: function() { 
                           
alert("Added!"); 
                       
} 
                   
});
               
} 
           
</script> 
        </div> 
    </section> 
    <section class="content-wrapper main-content
clear-fix"> 
        
        <div id="templates"
style="display:none"> 
            
           
<table> 
               

               
<tr class="row-template"> 
                   
<form> 
                   
<td class="Name"></td> 
                  
<td><input
type="button" value ="Change"
class="change"/></td> 

                   
<td><input type="button" value ="Del"
class="delete"/></td> 
                   
</form> 
               
</tr> 
                 

           
</table> 
        
        </div> 
            
<form id="frm"> 
                   
<input type="text" name="name" id="name"/> 
                   
<td><input type="button" value ="Add"
onclick="return addStudent();"/></td> 
                   

                   
</form> 

    </section> 

</div>
    </section> 
</div>

Let’s imitate behavior of creation, updating, and deleting operations with the help of curl and Fiddler. Note, that in curl the message body is created in a special way: if we have a complicated model, then we put name=Sychev, but if we have a simple model with one then we have to use -d "=Sychev".

POST:

PUT:

DELETE:

This happens if we return an error message to a client as an answer.

Congratulations, our REST-service at Web API using ASP.NET MVC and jQuery is complete. Now let’s have a look at some additional functionality.

Odata support in Web API

ASP.NET Web API has a built-in support of several parameters of Odata queries, e.g., sorting, filtering, and paging.

OData usage in Web API begins with a packet installation including a pack of dependencies with the help of NuGet,.

Substitute Get method content with the corresponding code.

 [Queryable(AllowedQueryOptions
= AllowedQueryOptions.All)] 
      public IQueryable<Student> Get() 
      { 
          return
_ctx.Student.AsQueryable(); 
      }

To use Odata method, we need to mark it as [Queryable] and tell it to return IQueryable. Serialization of Odata data will be performed in bit different way later on.

Now let’s add to WebApiConfig file in App_Start folder some sugar, coming later on. WebApiConfig code should looked as the code provided below.

  public
static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.AddQueryStringMapping("$format",
"json", "application/json"); 
       
GlobalConfiguration.Configuration.Formatters.XmlFormatter.AddQueryStringMapping("$format",
"xml", "application/xml");
       
GlobalConfiguration.Configuration.Formatters.XmlFormatter.AddQueryStringMapping("$format",
"xml", "application/xml");
       
config.Routes.MapHttpRoute( 
            name:
"DefaultApi", 
           
routeTemplate: "api/{controller}/{id}", 
            defaults:
new { id = RouteParameter.Optional } 
        ); 
    } 

Let’s run the project and follow http://localhost:[port]/api/values. XML will be printed, which is returned by OData.

Note that data is serializing in a bit different way, and this should be taken into account while developing.

Now we can use opportunities provided by OData. E.g., follow the link:

http://localhost:61020/api/values?$filter=(id eq 6)

Or:

http://localhost:61020/api/values?$filter=(id eq 6)&$format=json

Format is a nonstandard procedure, that we added into WebApiConfig file.

Using OData, we can interact with the server-stored data model with the help of format. Surely, we have to be careful despite the fact that Web API OData provides read only access to the data.

Thank you for attention.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)