This is a series of blogs detailing my introduction to using OData v4 with C# and ASP.NET WebApi.
The source code for the project can be found here.
Creating the Project
The Project is called Part08
Create the Customer Model
In the Models folder create a Customer class for our Entity.
public class Customer
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
Here we have added the Key attribute to the Id property.
Create a Data Source
For the purpose of testing we can just create an in-memory repository using Lists. In the real world you will need something like Entity Framework or another object relational mapping type application. This is to ensure that the backend systems are doing any filtering, etc and not the clients.
A folder called DataSource was created and within it a class called Repository.
Two methods were created. One to fetch all the customers and the other to fetch a customer by ID.
public IQueryable GetCustomers()
{
return _customers.AsQueryable();
}
public Customer GetCustomer(int id)
{
return _customers.Where(p => p.Id == id).FirstOrDefault();
}
Create the Entity Data Model (EDM)
We need to describe our Customer in the OData Entity Data Model. There is in fact a number of different ways we can do this however; that will be for a future blog. For this demo, I will use the most simplistic way to keep things simple.
Within the App_Start\WebApiConfig.cs file I created a GetEdmModel method to define our EDM.
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder _builder = new ODataConventionModelBuilder();
_builder.EntitySet("Customers");
return _builder.GetEdmModel();
}
We declare a new model, add an EntitySet called “Customers” based on our Customer type or Entity in this context. The EDM is then generated and returned from this method. It used the Key attribute on the Customer class to determine the key for the customer entity.
When you reach the section on Create an OData Route, it will explain where this method is called from.
Create Customers Controller
The OData implementation within WebApi uses convention over configuration. This means that if we declare our classes and methods using a specific naming standard, the correct methods will be found without having to define them. There will be times when the convention will not be suitable and we have the opportunity to declare what methods to use. Again, this will be discussed in future blogs as required.
The EDM we created above declared an EntitySet called Customers. This means we must create a controller called CustomersController. Within the controller we need to support two actions, one to fetch all the customers and the other to fetch a customer by Id.
public class CustomersController : ODataController
{
private Repository _repo;
public CustomersController()
{
_repo = new Repository();
}
// OData\Customers
public IQueryable Get()
{
return _repo.GetCustomers();
}
// OData\Customers(1)
public Customer Get([FromODataUri] int Key)
{
return _repo.GetCustomer(Key);
}
}
Our CustomersController inherits from ODataController which in turn inherits from ApiController with additional OData functionality.
All methods called by an OData request are decorated with the EnableQuery attribute.
For getting all customers it expects to find a method called Get or GetCustomers with no arguments and a return type that can return a collection of customers.
For getting a single customer it expects to find a method called Get or GetCustomer with an argument called Key and a return type of customer. The FromODataUri attribute is used for model binding and its informing the framework that the Key needs to be pulled from the Uri.
Create an OData Route
The last piece of configuration is defining the route much like we define the routes for WebApi, ASP.NET MVC, etc. The route maps a request to a specific controller name and action name. Any routes we define for OData will replace any WebApi routes that may also exist.
Within the App_Start\WebApiConfig.cs file there is already a Register method with the default WebApi route registration. We can delete the WebApi config if it is not required and just add the OData route.
public static void Register(HttpConfiguration config)
{
// OData Routing
config.MapODataServiceRoute("OData", "OData", GetEdmModel());
}
We use the MapODataServiceRoute method and declare a route called OData. The second argument with the value OData is used to define the OData Service name in the URI. We use http:///OData. If we set the value to NULL our URI will be http://.
The third argument is where we pass in our Entity Data Model.
Query all Customers
We are finished with the coding and can now test.
From Postman issue a GET request with http://localhost:40000/Customers to fetch all the customers.
Query One Customer
From Postman issue a GET request with http://localhost:40000/Customers(1) to fetch customer id 1.
What happens if we put an invalid ID in? We get back an ugly 500 error because we have not done any error handling. This is something that we need to consider when running in production. Look out for a future blog on this.
You may be thinking that so far OData is nothing special. We could have done the same thing with WebApi. That is true and if you google the differences it can be very confusing. The power comes from the url query options we can include to filter, sort, etc. We don’t need to code for every combination of data access that we would do with WebApi. We can let the framework tailor our server requests to only return the data the client asked for.
In the next blog we will continue our basic queries by looking at Composite Keys.