Adding a REST interface to your application using ASP.NET Web API is pretty well documented. This post describes the creation of an OData feed through the same ASP.NET Web API techniques. The example below uses an ASP.NET Web Forms application as the base since there are tons of these applications out there. You can use this same technique in MVC apps as well. Since everything in this environment is ASP.NET at the core, Web Forms, MVC and Web API can all exist side-by-side. The only assumption for this post is that the applications utilize .NET 4.5.
One other note, it is relatively easy to combine Entity Frameworks with OData output. This example describes the use of non-EF datasets. Why? you ask. Well, there may be many cases where the data is not coming from an EF source or maybe your data is stored or cached locally. There are any number of reasons. Ultimately, this example shows how to output your data in a standardized OData fashion including any part or all of the OData querying capabilities provided to the consumer of the service.
So, we start off with a standard Web Forms application. Steps 1 and 2 listed here are not absolutely necessary, they are meant to structure the application in a similar form to that of an ASP.NET MVC application. Doing this will make things it easier to manage. If you start off with an MVC application, the folders will already exist.
1. Create a sub folder right off the main project and call it “Controllers”
2. Create a second sub folder right off the main project and call it “Models”
The Models folder should contain classes created to shuffle data around the application. In an MVC application, view models can be held here to support and pass data to the views. In this example, we will be creating a model that will describe the data provided in the OData interface. The data here will be a simple list of meetings. Obviously, it could be any data you want but since we are using OData, it should start with a larger grouping (or groupings) of data. If your interface will always return a single a single record or object, then the non-OData Web API interfaces are better. But, if you are starting with a relatively large set of data and then (through queries) trim down the output to a smaller subset or even a single record, OData will work very well.
You should now have something that looks like this:
3. Add a class that will manage the meeting data:
using System; namespace FormsWithWebApiAndOData.Models { public class Meeting { public string Id { get; set; } public DateTime MeetingDate { get; set; } public string Title { get; set; } public string Leader { get; set; } } }
4. Add the controller that will provide all of the REST access. Right-click “Models” and add a “Web API Controller”. You can add this through the normal “Add Item” approach. You may also have a menu option to add the controller directly. Name the controller “MeetingsController.cs”. It is important that the name of the controller class ends in “Controller.cs” since ASP.NET MVC and Web API use “Convention over Configuration”. Naming convention is the way many components are found as the application executes.
You will now have a project structure that looks something like this:
The application must understand how to process requests that are destined for the OData REST service that we are creating. To do this, the application must contain the ASP.NET Web API and Odata components (assemblies). This is easy to do through NuGet.
5. Right-click on the project and select “Manage NuGet Packages…”. When the NuGet dialog appears, enter the following search to make things easier: “ASP.NET Web API OData”. When the package appears, click “Install”.
We can now add the OData functionality. The controller must be modified to provide the OData REST access point to the Meeting data. We need to add some code to create the data that is used in the example.
6. Open MeetingsController.cs and add the following code at the top of the class. It will then be the source of the OData feed.
private readonly IList<Meeting> _scheduledMeetings; public MeetingsController() { _scheduledMeetings = new List<Meeting> { new Meeting { Id = "1", Leader = "Mark Nichols", MeetingDate = new DateTime(2013, 1, 17), Title = "Project X Planning" }, new Meeting { Id = "3", Leader = "Jim Phelps", MeetingDate = new DateTime(2013, 2, 8), Title = "Mission Discussion" }, new Meeting { Id = "6", Leader = "Barney Collier", MeetingDate = new DateTime(2013, 3, 12), Title = "Advanced Device Technology" }, new Meeting { Id = "7", Leader = "Willie Armitage", MeetingDate = new DateTime(2013, 5, 28), Title = "Maintaining a Strong Presence" }, new Meeting { Id = "9", Leader = "Cinnamon Carter", MeetingDate = new DateTime(2013, 2, 15), Title = "Company Fashion" }, new Meeting { Id = "10", Leader = "Rollin Hand", MeetingDate = new DateTime(2013, 1, 21), Title = "Magic Selling" } }; }
Web API injects a standard set of methods for HTTP GET, POST, DELETE, and PUT to get you started. In this example are really only interested in a GET that will allow all necessary OData queries so you can actually delete all of the provided methods. We’ll add our own GET in the next step.
7. Add the following method to the controller right below the constructor code you added in the last step.
// GET api/Meeting [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)] public IQueryable<Meeting> Get() { return _scheduledMeetings.AsQueryable(); }
You will need to add these “using” statements:
using System.Web.Http.OData.Query; using FormsWithWebApiAndOData.Models;
Notes on the HTTP GET method that we just added:
- “IQueryable” (part of Linq) is the interface that you must return so that OData can provide the appropriate query and output capabilities.
- The List that contains all of the meeting data can be made to output its data through the IQueryable interface by using the “AsQueryable()” extension method (also provided by Linq).
- The attribute “QueryableAttribute” enables querying using the OData syntax.
- AllowedQueryOptions provides an easy mechanism for limiting the types of queries that are allowed to be processed. This is especially important when dealing with significant amounts of data. You can stop queries that would normally spend tons of time processing on your server. In this example, I’ve opened up all queries so you can try all of the OData options.
We’re almost done. Lastly, we need to create a URL path that will send OData requests to the method that we just created.
8. Open Global.asax and in Application_Start add the routing information that will transfer control to the newly created method.
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "ODataRestApi",
routeTemplate: "api/v1/{controller}"
);
“MapHttpRoute” sets up the URL routing information so that everything can flow through the controller we just created and then into the method. “name” is arbitrary and has no effect on the routing – it is just for organizational purposes. “routeTemplate” indicates what URL pattern will be captured. In this case the URL must start with “api” and then, it must contain “v1”. The “v1” is an indicator of the version of the API. Version your API’s and you will always be better off. “{controller}” acts as a variable and captures the name of the controller that contains the functionality that you want to call. In our case, the name of the controller is “MeetingsController” but because of convention, only the “Meetings” part must be used, the ASP.NET frameworks take care of the rest of the mapping.
The only thing left to do is run it. Execute the application and try some of the following queries (port number will vary of course):
http://localhost:14129/api/v1/meetings
http://localhost:14129/api/v1/meetings?$filter=(Leader eq ‘Mark Nichols’)
http://localhost:14129/api/v1/meetings?$top=2
http://localhost:14129/api/v1/meetings?$filter=MeetingDate eq datetime’2013-01-17′
You now have OData query control over pretty much any kind of data you want to pump through your API. You can use these queries in AJAX calls or even right from your browser.
Formatting the Output
This part is not necessary for the operation of the queries BUT you may want to control the data format coming back through the optional OData “format’=” query parameter. This capability is always there through setting the content headers in the HTTP request but OData gives you another option in the query. You just have to turn it on:
In my tests, if I used Internet Explorer (I was using V10), all my requests would return JSON data. If I used Chrome, XML would always come back. So, I added the some code to give me the option of XML or JSON in the query.
Add the following code in Global.asax right before the call to MapHttpRoute :
// XML or JSON output selection GlobalConfiguration.Configuration.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json"); GlobalConfiguration.Configuration.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");
You will need to add this using statement:
using System.Net.Http.Formatting; // "AddQueryStringMapping"
Now you should be able to do things like this:
http://localhost:14129/api/v1/meetings?$filter=(Leader eq ‘Mark Nichols’)&$format=xml
http://localhost:14129/api/v1/meetings?$top=2&$format=json
References:
OData Developers Reference: http://www.odata.org/developers/
OData in ASP.NET: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api
Limiting OData Query Options: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
OData Security: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-security-guidance
OData is Case Sensitive!
One last thing, the OData query syntax is case sensitive. So, if you don’t get back what you think you should have with a particular query, check the case of the query commands (usually lower case), filter fields (depends on your data classes), etc.

