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.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace OdataAPI.Models
- {
- public class company
- {
- public int Id { get; set; }
- public string name { get; set; }
- public string location { get; set; }
- }
-
- public class company_rep
- {
- public static List<company> list = null;
- static company_rep()
- {
- list = new List<company>();
- list.Add(new company { Id = 1, location = "kolkata", name = "TCS" });
- list.Add(new company { Id = 1, location = "Delhi", name = "Wipro" });
- list.Add(new company { Id = 1, location = "Bangalore", name = "IBM" });
- }
- }
- }
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.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web.Http;
- using System.Web.Http.OData.Builder;
- using Microsoft.Data.Edm;
- using OdataAPI.Models;
-
- namespace OdataAPI
- {
- public static class WebApiConfig
- {
- private static IEdmModel GenerateEdmModel()
- {
- var builder = new ODataConventionModelBuilder();
- builder.EntitySet<company>("companyProcessing");
- return builder.GetEdmModel();
- }
-
- public static void Register(HttpConfiguration config)
- {
-
- config.MapHttpAttributeRoutes();
- config.EnableQuerySupport();
- config.Routes.MapODataRoute("odata", "odata", GenerateEdmModel());
- config.Routes.MapHttpRoute(
- name: "DefaultApi",
- routeTemplate: "api/{controller}/{id}",
- defaults: new { id = RouteParameter.Optional }
- );
- }
- }
- }
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.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Web;
- using System.Web.Http;
- using System.Web.Http.OData;
- using System.Web.Http.OData.Routing;
- using System.Web.Mvc;
- using OdataAPI.Models;
-
- namespace OdataAPI.Controllers
- {
- public class companyProcessingController : ODataController
- {
-
- public IQueryable<company> Get()
- {
- return company_rep.list.AsQueryable();
- }
-
- public HttpResponseMessage Get([FromODataUri]int key)
- {
- company com = company_rep.list.Where(e => e.Id == key).SingleOrDefault();
- if (com == null)
- {
- return Request.CreateResponse(HttpStatusCode.NotFound);
- }
- return Request.CreateResponse(HttpStatusCode.OK, com);
- }
-
- public HttpResponseMessage Post([FromBody]company entity)
- {
- HttpResponseMessage response;
- try
- {
- company_rep.list.Add(entity);
- response = Request.CreateResponse(HttpStatusCode.Created, entity);
- response.Headers.Add("Location", Url.ODataLink(new EntitySetPathSegment("companyProcessing")));
- return response;
- }
- catch (Exception)
- {
- response = Request.CreateResponse(HttpStatusCode.InternalServerError);
- return response;
- }
- }
-
-
- public HttpResponseMessage Put([FromODataUri]int key, [FromBody]company company)
- {
- var employeeToDeleteEdit = company_rep.list.Where(e => e.Id == key).FirstOrDefault();
- HttpResponseMessage response;
- string location = company.location;
- string name = company.name;
- int index = company_rep.list.FindIndex(e => e.Id == key);
- if (index >= 0)
- {
- company_rep.list[index].name = name;
- company_rep.list[index].location = location;
- }
- else
- {
- response = Request.CreateResponse(HttpStatusCode.NotFound);
- return response;
- }
- response = Request.CreateResponse(HttpStatusCode.OK, company);
- return response;
- }
-
- public HttpResponseMessage Delete([FromODataUri]int key)
- {
- var employeeToDelete = company_rep.list.Where(e => e.Id == key).FirstOrDefault();
- if (employeeToDelete != null)
- {
- company_rep.list.Remove(employeeToDelete);
- return new HttpResponseMessage(HttpStatusCode.OK);
- }
- else
- {
- throw new HttpResponseException(HttpStatusCode.NotFound);
- }
- }
- }
- }
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.
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)
Here we are getting only one company information.
Post operationNow 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
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.
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.
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.