swirl
Home Software Blog Wallpapers Webtools
OData V4 - Primer
Friday 05, February 2016   |   Post link   |   Sample code  Download related material

Topic covered

  • Use Microsoft OData v4 library with ASP.NET Web API
  • Implement CRUD methods on complex types using Microsoft oData (v4.0) library
  • Brief look at built in filtering mechanism

Introduction

If you're reading this article there's a good chance you already know about oData - what it is and why you want to use it. OData is a standard for querying for information and is built on top of REST. It standardizes certain query operations like limiting number of returned objects, performing paging, counting returned elements, selecting objects based on conditions and many more. It's an open protocol and is gaining support from number of informaiton providers like SalesForce, Netflix and others.There are a number of good introductory articles on oData like this one: https://msdn.microsoft.com/en-us/data/hh237663.aspx.

Source code for the sample application

Download the source code from the link 'Download related material' link under the title. Nuget packages required for building the sample have been deleted to reduce the size of the download. To build the solution correctly, open the ODataMovies.sln file and go to the main-menu -> Toos -> Nuget Package Manager -> Manage Nuget Packages for solution -> In the top bar click the Restore button - this should download required OData packages from Nuget.

Sample scenario

For this article we'll be exposing movies via oData. A Movie has an id, title, rating, last-modified-timestamp, director. Rating is an enumeration of stars from one to five, director is a Person which has a first-name and a last-name. These classes make up the 'model' of our application.

OData services can be written using WCF or ASP.NET Web API. In this article we'll use ASP.NET Web API. We'll call the project ODataMovies and make the data available under the uri /odata. This means all endpoints will have an address like: http://localhost/odata/

Creating the project

Fire up Visual Studio 2015 and create a new Web Project. In the following screen select:
  • Select Empty from the ASP.NET 4.5.2 Templates.
  • Uncheck the 'Host in the cloud' checkbox.
  • Uncheck 'Web Forms' and 'MVC' checkboxes.
  • Select only the Web API checkbox.

Install oData Nuget package

From the main menu select Tools -> NuGet Package Manager -> Package Manager Console. At the PM> prompt enter:
Install-Package Microsoft.AspNet.OData -Version 5.8.0 
I am explicitly specifying the version here. You may not be needed. As of this writing, 5.8.0 is the latest version and this is what will get installed if you don't specify the version explicitly. Having said that, the oData team seems to be changing some classes and even removing some like EnititySetManager which was present in earlier version so locking down the version will ensure that the project will work even if new version of oData is released.

Add the model classes

First we'll add the model classes which are Movie, Person and an enum called StarRating. Its a good idea to create these .cs files within the Models folder though its not necessary. We will be exposing only the Movie object via our oData service.

Enable oData routing

Routing refers to understanding the URL format and translating that to method calls. For e.g. if someone accesses http://localhost/odata/Movies, this should fire a method where we can write code to access movie objects and make them available to the client. This routing setup is done in the App_Start/WebApiConfig.cs file. Replace the existing code in the Register method with:

Writing the business layer

We'll have a thin business layer which will provide services to store and retrieve model objects i.e. the movie objects.
Create a new folder called Business. Create a new file named DataService.cs. Instead of actually storing the data in a database, we'll just work with an in memory list of model objects.

Enabling the oData (REST) methods

In order to serve oData request we need to create a controller class. A controller is responsible for managing a resource, for us the resource is the movie collection. When we registered the route, the following line exposed the movie resource:
modelBuilder.EntitySet("Movies"); // We are exposing only Movies via oData
This implies that we should create a controller class named MoviesController. Methods to handle various Http verbs like Get, Post, Put & others are implemented by methods of the same name e.g. to handle a Post verb, write a method called Post.
Let's first expose the movie collection. Create a class called MoviesController which derives from ODataController. Compile and run the project by hitting F5. Type in the following url in a browser: http://localhost:32097/odata/Movies
Note: replace the 32097 port with your port. You should see a JSON response like:
{
  "@odata.context":"http://localhost:32097/odata/$metadata#Movies","value":[
    {
      "Id":1,"Title":"StarWars - The Force Awakens","ReleaseDate":"2015-10-25T00:00:00+05:30","Rating":"FiveStar","Director":{
        "FirstName":"J.J.","LastName":"Abrams"
      },"LastModifiedOn":"2016-01-26T13:29:10.2039858+05:30"
    },{
      "Id":2,"Title":"Mad Max - The Fury Road","ReleaseDate":"2015-05-15T00:00:00+05:30","Rating":"FourStar","Director":{
        "FirstName":"George","LastName":"Miller"
      },"LastModifiedOn":"2016-01-26T13:29:10.2044867+05:30"
    }
  ]
}
That's quite cool to be able to expose data so easily. Not just that, try this:
http://localhost:32097/odata/Movies?$top=1
You'll see a just one record.

OData has a number of filters like eq, gt, lt and many more. Let's try the eq filter: http://localhost:32097/odata/Movies?$filter=Title%20eq%20%27Mad%20Max%20-%20The%20Fury%20Road%27

The result will match the movie which has the title 'Mad Max - The Fury Road'. This magic is happening because of oData library which we are using. Since we used the [EnableQuery] attribute, oData library is adding a filter to the result-set. When working with EF (Entity Framework), it may be better to return IQueryable to leverage features like deferred execution and query optimization.

Retrieving a specific item

Retrieving a specific item is also handled by the GET verb, we just need some additional information in the url. Add the following code in the controller class: To invoke this url, use a url like: http://localhost:32097/odata/Movies(1). Here 1 is the ID or key. Since we are using 5.8.0 oData library it's not necessary to use the [FromODataUri] attribute, even if you do remove it, the code will work just fine.

Adding an item

Having enabled fetching data by implementing Get, lets implement adding a new movie. Adding items is usually handled by using the POST verb. The data is sent along with the body of the http request. Since we are using 5.8.0, there is no need to specify the [FromBody] attribute e.g. public IHttpActionResult Post([FromBody] Movie movie). To test this, you'll need an application which can make HTTP POST requests and pass along headers and content like Telerik's Fiddler. Get it from www.telerik.com/fiddler, its free.

Build the project & launch it by hitting F5 in Visual Studio. Launch Fiddler after installing it. In Fillder do the following:
  • Click the 'Composer' tab. Copy the url from the browser which was launched by Visual Studio and modify the url to: http://localhost:32097/odata/Movies and paste it in the address textbox.
  • Select 'POST' from the dropdown
  • Enter Content-Type: Application/JSon in the header textbox.
  • Paste
    { "Id":1,"Title":"Transformers - 4","ReleaseDate":"2015-10-25T00:00:00+05:30","Rating":"FiveStar","Director":{ "FirstName":"Not","LastName":"Sure" } }
    into the request body textbox.
  • Hit execute.
Here is a screenshot of the request:

On Fiddler's left pane you should see your request. Double click to see the details:

The important thing to notice is that we got back HTTP status code of 200 which means OK. The response text contains a JSON object which is the newly created movie object, check the Id; its 3.

Implementing PUT

PUT method is used to update an existing resource. Paste the following code in the controller to implement PUT. Note, we could even implement the method like: In this case if we want to communicate back errors, we need to throw HttpResponseException with the correct HTTP error code. In the previous case we could just return the HTTP status using methods like NotFound(). When you throw an HttpResponseException its converted to an http status by the Web API framework anyway.

Let's hit the method using Fiddler using the URL http://localhost:32097/odata/Movies(2). We must be careful to specify the proper HTTP header which in this case is:
Content-Type: Application/Json

The properties we want to update against the movie having the id 2 needs to be specified in the request body. Even the properties which haven't changed need to be specified as PUT is supposed to blindly update all the properties. For this example, et's try to give FiveStars to Mad-Max. Use the following text in the request body:
{
      "Id":2,"Title":"Mad Max - The Fury Road","ReleaseDate":"2015-05-15T00:00:00+05:30","Rating":"FiveStar","Director":{
        "FirstName":"George","LastName":"Miller" }
}
Here's a screenshot of how the request looks in Fiddler's composer:

Implementing DELETE

Delete is implemented the same way. Note that if a key is not found, we return the appropriate HTTP status code which is NOT FOUND. To test DELETE, use Fiddler and select the 'DELETE' verb. We need to specify which object to delete by its id. This is done by a url of the following format: http://localhost:32097/odata/Movies(2) This will delete the movie with id = 2.

Implementing PATCH

The last method we'll implement is PATCH. This method is like PUT except that in PUT all the properties of the passed-in object are copied into an exisitng object, where as in PATCH, only properties that have changed are applied to an exisitng object. Property changes are passed using the Delta class object. This is a template class which defined as method named CopyChangedValues() which copies the changed properties to the target object. To invoke the patch method, use the url http://localhost:32097/odata/Movies(1).
This will apply the properties to the movie having id = 1.
Set the content-type to Application/Json and select 'PATCH' verb in Fiddler.
In case of success, we are returning HTTP status code OK (200) and also returning the entire object in JSON format in the response body.

Summary

To conclude, oData formalizes exposing resources and supporting CRUD operations pretty well. The oData library provides useful filtering options which you get for free by using the [EnableQuery] attribute on the controller methods. Finally, the oData library and ASP.NET Web API make creating oData services extremely easy.
Sample code  Download related material


Comments

Posts By Year

2024 (4)
2023 (5)
2022 (10)
2021 (5)
2020 (12)
2019 (6)
2018 (8)
2017 (11)
2016 (6)
2015 (17)
2014 (2)
2013 (4)
2012 (2)

Posts By Category

.NET (4)
.NET Core (2)
ASP.NET MVC (4)
AWS (5)
AWS API Gateway (1)
Android (1)
Apache Camel (1)
Architecture (1)
Audio (1)
Azure (2)
Book review (3)
Business (1)
C# (3)
C++ (2)
CloudHSM (1)
Containers (4)
Corporate culture (1)
Database (3)
Database migration (1)
Desktop (1)
Docker (1)
DotNet (3)
DotNet Core (2)
ElasticSearch (1)
Entity Framework (3)
Git (3)
IIS (1)
JDBC (1)
Java (10)
Kibana (1)
Kubernetes (1)
Lambda (1)
Learning (1)
Life (7)
Linux (2)
Lucene (1)
Multi-threading (1)
Music (1)
OData (1)
Office (1)
PHP (1)
Photography (1)
PowerShell (2)
Programming (28)
Python (1)
Rants (5)
SQL (2)
SQL Server (1)
Security (3)
Software (1)
Software Engineering (1)
Software development (2)
Solr (1)
Sql Server (2)
Storage (1)
T-SQL (1)
TDD (1)
TSQL (5)
Tablet (1)
Technology (1)
Test Driven (1)
Testing (1)
Tomcat (1)
Unit Testing (1)
Unit Tests (1)
Utilities (3)
VC++ (1)
VMWare (1)
VSCode (1)
Visual Studio (2)
Wallpapers (1)
Web API (2)
Win32 (1)
Windows (9)
XML (2)

Posts By Tags

.NET(6) API Gateway(1) ASP.NET(4) AWS(3) Adults(1) Advertising(1) Android(1) Anti-forgery(1) Asynch(1) Authentication(2) Azure(2) Backup(1) Beliefs(1) BlockingQueue(1) Book review(2) Books(1) Busy(1) C#(4) C++(3) CLR(1) CORS(1) CSRF(1) CTE(1) Callbacks(1) Camel(1) Certificates(1) Checkbox(1) Client authentication(1) CloudHSM(1) Cmdlet(1) Company culture(1) Complexity(1) Consumer(1) Consumerism(1) Containers(3) Core(2) Custom(2) DPI(1) Data-time(1) Database(4) Debugging(1) Delegates(1) Developer(2) Dockers(2) DotNetCore(3) EF 1.0(1) Earphones(1) Elastic Search(2) ElasticSearch(1) Encrypted(1) Entity framework(1) Events(1) File copy(1) File history(1) Font(1) Git(2) HierarchyID(1) Hyper-V(1) IIS(1) Installing(1) Intelli J(1) JDBC(1) JSON(1) JUnit(1) JWT(1) Java(3) JavaScript(1) Kubernetes(1) Life(1) LinkedIn(1) Linux(2) Localization(1) Log4J(1) Log4J2(1) Logging(1) Lucene(1) MVC(4) Management(2) Migration history(1) Mirror(1) Mobile Apps(1) Modern Life(1) Money(1) Music(1) NGINX(1) NTFS(1) NUnit(2) OData(1) OPENXML(1) Objects(1) Office(1) OpenCover(1) Organization(1) PHP(1) Paths(1) PowerShell(2) Processes(1) Producer(1) Programming(2) Python(2) QAAC(1) Quality(1) REDIS(2) REST(1) Runtimes(1) S3-Select(1) SD card(1) SLF4J(1) SQL(2) SQL Code-first Migration(1) SSH(2) SSL(1) Sattelite assemblies(1) School(1) Secrets Manager(1) Self reliance(1) Service(1) Shell(1) Solr(1) Sony VAIO(1) Spirituality(1) Spring(1) Sql Express(1) System Image(1) TDD(1) TSQL(3) Table variables(1) Tables(1) Tablet(1) Ubuntu(1) Url rewrite(1) VMWare(1) VSCode(1) Validation(2) VeraCode(1) Wallpaper(1) Wallpapers(1) Web Development(4) Windows(2) Windows 10(2) Windows 2016(2) Windows 8.1(1) Work culture(1) XML(1) Yii(1) iTunes(1) open file handles(1) renew(1) security(1) static ip address(1) ulimit(1)