Getting started with OData in ASP.NET Core
November 06, 2017 by Anuraj
ASP.NET Core OData
This post is about getting started with OData in ASP.NET Core. OData (Open Data Protocol) is an ISO/IEC approved, OASIS standard that defines a set of best practices for building and consuming RESTful APIs. OData helps you focus on your business logic while building RESTful APIs without having to worry about the various approaches to define request and response headers, status codes, HTTP methods, URL conventions, media types, payload formats, query options, etc. OData also provides guidance for tracking changes, defining functions/actions for reusable procedures, and sending asynchronous/batch requests.
ASP.NET Core didn’t support OData officially. This blog post using a NuGet package, which looks like official, but it is not.
First you need to create a Web API project with dotnet command. Once it is created, you need to add the OData package to your project, you can use the following command to do it.
dotnet add package Microsoft.AspNetCore.OData --version 1.1.0-alpha1
Next you need to create a model class and DBContext class. I am using an InMemory database. Here is the model class and DB Context class.
public class Person
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int Age { get; set; }
}
public class SampleODataDbContext : DbContext
{
public SampleODataDbContext(DbContextOptions options) : base(options)
{
}
protected SampleODataDbContext()
{
}
public DbSet<Person> Persons { get; set; }
}
Next you need to create a Controller, in earlier versions of OData you can inherit from ODataController. But in ASP.NET Core, there is no OData controller available. So you need to create a normal controller, with OData attributes.
public class PersonController : Controller
{
private readonly AppDbContext _appDbContext;
public PersonController(AppDbContext sampleODataDbContext)
{
_appDbContext = sampleODataDbContext;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(_appDbContext.Persons.AsQueryable());
}
}
For EnableQuery attribute you require “Microsoft.AspNetCore.OData” namespace. Finally, you need to modify your startup class code to add OData middleware and OData routing.
public void ConfigureServices(IServiceCollection services)
{
//Adding In Memory Database.
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDb");
});
//Adding OData middleware.
services.AddOData();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//Adding Model class to OData
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>(nameof(Person));
//Enabling OData routing.
app.UseMvc(routebuilder =>
{
routebuilder.MapODataRoute("odata", builder.GetEdmModel());
});
}
Without the routing prefix - OData in this example, all the routes will be redirected to OData endpoints.
And here is the output of $metadata endpoint.
While developing the application, I faced three issues.
- InvalidOperationException: Cannot resolve scoped service ‘Microsoft.OData.ODataSimplifiedOptions’ from root provider.
I got this exception while working with application. I had to spent some time exploring this issue. And finally resolved it by adding following code in Main()
method in program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
.Build();
}
- Some serialization exception while returning
SingleResult
from controller action -
[EnableQuery]
public SingleResult Get(int id)
{
var result = _appDbContext.Persons.Where(p => p.Id == id);
return SingleResult.Create(result);
}
Unfortunately, I was not able to fix this exception. As a workaround, I did something like this.
[EnableQuery]
public IActionResult Get(int id)
{
var result = _appDbContext.Persons.FirstOrDefault(p => p.Id == id);
return Ok(result);
}
- HTTP PUT was not working - Due to some strange issues, HTTP PUT was not working. It is always returning 404. I was not able to resolve this issue and I don’t have any workarounds for this.
Source code available on GitHub
Happy Programming :)
Copyright © 2025 Anuraj. Blog content licensed under the Creative Commons CC BY 2.5 | Unless otherwise stated or granted, code samples licensed under the MIT license. This is a personal blog. The opinions expressed here represent my own and not those of my employer. Powered by Jekyll. Hosted with ❤ by GitHub