Expose Odata Endpoints Without Entity Framework and Performing CRUD

This article explains odata endpoints without Entity Framework and performing CRUD.

Sorry for the bad and irrelevant title first of all. But have you ever thought, is it really possible to expose any Odata service without Entity Framework?  A few days ago I was talking with one of my fellow developers and in a word the topic raised was that we were thinking, if there is another data source other than Database or Entity Framework? How can we expose data as an Odata service?

Then I started to develop one POC to prove that yes, we can expose data without using the Entity Framework, if we think a little bit then we will get the answer ourself.  We know that Odata is nothing but an endpoint or data source that allows a set of data access mechanisms to suck data from it where the underlying concept to bring data up to the endpoint is totally abstract to the end user.

So, there might be n number of ways to bring data to an endpoint but the Odata endpoint will use the uniform mechanism to expose the data with the outside world, irrespective of client and platform. So the ultimate point is that there is not a strong relationship with the Entity Framework and Odata. But when people talk about Odata/MVC and the Web API then automatically the Entity Framework is related if the underlying data source is a SQL table / database.

Fine, now let's see how to implement an Odata endpoint with our custom class. First of all create one Web API 2.0 project to the solution and enable Odata in it. You can install an Odata related package from the NuGet Package Manager.

Once it is finished create one model class to use the class as the data source. Here I have created a sample one.

  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Linq;   
  4. using System.Web;      
  5.   
  6. namespace OdataAPI.Models   
  7. {   
  8.     public class company   
  9.     {   
  10.         public int Id { getset; }   
  11.         public string name { getset; }   
  12.         public string location { getset; }   
  13.     }  
  14.   
  15.     public class company_rep   
  16.     {   
  17.         public static List<company> list = null;   
  18.         static company_rep()   
  19.         {   
  20.             list = new List<company>();   
  21.             list.Add(new company { Id = 1, location = "kolkata", name = "TCS" });   
  22.             list.Add(new company { Id = 1, location = "Delhi", name = "Wipro" });   
  23.             list.Add(new company { Id = 1, location = "Bangalore", name = "IBM" });   
  24.         }   
  25.     }   

The implementation is a very simple. company class; it is our main model class and the “company_rep” will work as the repository and it will supply the data.

Fine, now we need to register our Odata endpoint to the routing.  Open the “WebApiConfig.cs ” file of the application and modify the code accordingly.

  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Linq;   
  4. using System.Web.Http;   
  5. using System.Web.Http.OData.Builder;   
  6. using Microsoft.Data.Edm;   
  7. using OdataAPI.Models;      
  8.   
  9. namespace OdataAPI   
  10. {   
  11.     public static class WebApiConfig   
  12.     {   
  13.         private static IEdmModel GenerateEdmModel()   
  14.         {   
  15.             var builder = new ODataConventionModelBuilder();   
  16.             builder.EntitySet<company>("companyProcessing");   
  17.             return builder.GetEdmModel();   
  18.         }  
  19.   
  20.         public static void Register(HttpConfiguration config)   
  21.         {   
  22.             // Web API routes   
  23.             config.MapHttpAttributeRoutes();        
  24.             config.EnableQuerySupport();   
  25.             config.Routes.MapODataRoute("odata""odata", GenerateEdmModel());        
  26.             config.Routes.MapHttpRoute(   
  27.                 name: "DefaultApi",   
  28.                 routeTemplate: "api/{controller}/{id}",   
  29.                 defaults: new { id = RouteParameter.Optional }   
  30.             );   
  31.         }   
  32.     }   

Have a look at GenerateEdmModel() function. In this function we are registering the model. Just create one Object of OdataConvertionModelBuilder class and register it.

Now, we will create one controller class where we will process our data. Have a look at the following example.

  1. using System;  
  2. using System.Collections.Generic;   
  3. using System.Linq;   
  4. using System.Net;   
  5. using System.Net.Http;   
  6. using System.Web;   
  7. using System.Web.Http;   
  8. using System.Web.Http.OData;   
  9. using System.Web.Http.OData.Routing;   
  10. using System.Web.Mvc;   
  11. using OdataAPI.Models;      
  12.   
  13. namespace OdataAPI.Controllers   
  14. {   
  15.     public class companyProcessingController : ODataController   
  16.     {   
  17.         //Read Data from list   
  18.         public IQueryable<company> Get()   
  19.         {   
  20.             return company_rep.list.AsQueryable();   
  21.         }              
  22.         //Fetch company information by Id   
  23.         public HttpResponseMessage Get([FromODataUri]int key)   
  24.         {   
  25.             company com = company_rep.list.Where(e => e.Id == key).SingleOrDefault();   
  26.             if (com == null)   
  27.             {   
  28.                 return Request.CreateResponse(HttpStatusCode.NotFound);   
  29.             }        
  30.             return Request.CreateResponse(HttpStatusCode.OK, com);   
  31.         }        
  32.         // Insert new company information   
  33.         public HttpResponseMessage Post([FromBody]company entity)   
  34.         {   
  35.             HttpResponseMessage response;   
  36.             try   
  37.             {                  
  38.                 company_rep.list.Add(entity);  
  39.                 response = Request.CreateResponse(HttpStatusCode.Created, entity);   
  40.                 response.Headers.Add("Location", Url.ODataLink(new EntitySetPathSegment("companyProcessing")));   
  41.                 return response;   
  42.             }   
  43.             catch (Exception)   
  44.             {   
  45.                 response = Request.CreateResponse(HttpStatusCode.InternalServerError);   
  46.                 return response;   
  47.             }   
  48.         }      
  49.   
  50.         //Update company information   
  51.         public HttpResponseMessage Put([FromODataUri]int key, [FromBody]company company)   
  52.         {   
  53.             var employeeToDeleteEdit = company_rep.list.Where(e => e.Id == key).FirstOrDefault();   
  54.             HttpResponseMessage response;   
  55.             string location = company.location;   
  56.             string name = company.name;        
  57.             int index = company_rep.list.FindIndex(e => e.Id == key);   
  58.             if (index >= 0)   
  59.             {   
  60.                 company_rep.list[index].name = name;   
  61.                 company_rep.list[index].location = location;   
  62.             }   
  63.             else   
  64.             {   
  65.                 response = Request.CreateResponse(HttpStatusCode.NotFound);   
  66.                 return response;   
  67.             }   
  68.             response = Request.CreateResponse(HttpStatusCode.OK, company);   
  69.             return response;   
  70.         }        
  71.         //Delete Company Information   
  72.         public HttpResponseMessage Delete([FromODataUri]int key)   
  73.         {   
  74.             var employeeToDelete = company_rep.list.Where(e => e.Id == key).FirstOrDefault();  
  75.             if (employeeToDelete != null)   
  76.             {   
  77.                 company_rep.list.Remove(employeeToDelete);   
  78.                 return new HttpResponseMessage(HttpStatusCode.OK);   
  79.             }   
  80.             else   
  81.             {   
  82.                 throw new HttpResponseException(HttpStatusCode.NotFound);   
  83.             }   
  84.         }   
  85.     }   

Get operation

When we hit the following URL, it will return all the data:
 
http://localhost:10020/odata/companyProcessing

Currently we have the information for 3 companies in our repository.

repository

If we want to get specific company information then we can supply the company Id as in the following:

http://localhost:10020/odata/companyProcessing(2)
 
get particular information

Here we are getting only one company information.
 
Post operation

Now we want to create new company information in the repository and for that we need to send a JSON payload to the controller. Here is one sample of JSON data for demonstration.

 { "Id": 4 , "location" : "Bangalore", "name" :"Timken" }

And once we hit the following URL, we will see that one new record has been created and the status code is 201.

http://localhost:10020/odata/companyProcessing
 
url

Put Operation

Now, when we want to update one existing record in the repository, we can use a Put operation. Here is the URL for where we want to perform the Put.

http://localhost:10020/odata/companyProcessing(3)

And the JSON payload that will modify the existing record is as in the following.

{ "Id": 3 , "location" : "USA", "name" :"Timken" }

And in Fiddler we are getting the output from the modification of record number 3.
 
Put Operation

 Delete operation

When we want to remove an item from the repository, we can do a Delete operation. In this example we are deleting the first record.
 
Delete operation

Conclusion

We have seen how smoothly we can expose Odata endpoints from our Custom data source (here class) without touching the Entity Framework and SQL Server. I hope you have understood it. Happy learning.