Up & Running w/ OData in ASP.NET 6

Hassan

Few months ago our .NET team announced a newer version of the .NET framework which continues the efforts to deliver the final parts of the .NET unifications plan that started with .NET 5. The newer version is .NET 6, which comes in with more powerful features, configurability, pluggability and extensibility across many platforms.

On top of that comes ASP.NET 6, Blazor, MAUI and so many other capabilities that makes the new foundational framework the perfect choice for software engineers building anything, anywhere.

Since the announcement, our OData team has been working diligently to give OData the capabilities it needs to stay current with the ground-breaking changes that have been going across all different parts of the .NET foundation.

In this article, I’m going to walk you step-by-step through the new way you can get up and running with OData on your ASP.NET 6.0 API in the simplest way possible. It is really important to remember that the engineering experience and ease of use to our OData library is a top priority before anything and everything else.

Let’s get started with OData in ASP.NET 6!

 

Setting Things Up

Let’s start by setting things up in our environment. It’s really important to point out that we will be using bleeding edge non-production ready technologies throughout this tutorial to give you a look and feel of the latest and greatest technologies Microsoft has to offer. Giving you a glimpse into the future and getting you up to speed in practice with what to expect in the future of engineering ASP.NET + OData solutions.

 

Bleeding Edge Tech

We will be using Visual Studio 2022 along with an installation of the latest version of .NET 6.0 through this tutorial. Please make sure you have these tools installed to get the exact same experience with OData on ASP.NET 6 I will be showing you here in this article.

While I urge you to download and install some additional newer technologies to get to experiment with our latest software, you may still be able to get things running with Visual Studio 2019 – but the .NET 6.0 is going to be a must-have for this tutorial.

Now, let’s jump to the next part of setting things up. Creating a new ASP.NET 6 solution and adding OData.

 

File ➡ New ➡ Project

In Visual Studio, start a new project, and select ASP.NET Core Web API Template as follows:

Image VS2022NewProject

If you have successfully installed .NET 6 on your local machine, you should be prompted to select the version with the follow dialog:

Image SelectDotNet6

 

Installing OData

Now that we have an up and running ASP.NET 6 project. I highly recommend you make sure things are running before you take any further steps with OData. The template usually comes with a WeatherForecastController which returns a list of random weather forecasts and a functional swagger document as follows:

Image SwaggerOData6

 

With a functional sample API, let’s go ahead and install the latest version of OData from “Manage Nuget Package” option on your solution as follows:

Image SelectOdata8

Now that we have OData 8.0.1 installed, let’s go to the most amazing part about the newer version of OData. The configurations!

 

Up & Running

In the past, we needed to take as many as four steps to get OData configured for our ASP.NET projects. This time things got much, much simpler! Let me show you how!

 

Startup.cs

In your Startup.cs file, add this simple line to your AddControllers() call as follows:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddOData(options => options.Select().Filter().OrderBy());

    ...
}

 

This simple configuration allows your ASP.NET 6.0 API to be OData-enabled instantaneously. Now the last step!

 

Controllers

In the existing WeatherForecastController simply add the good old EnableQuery

decoration to your controller method as follows:

[HttpGet]
[EnableQuery]
public IEnumerable<WeatherForecast> Get()
{
   ...
}

And with that, we are now ready to consume our endpoint with OData protocols. Let’s give it a shot!

 

Going Live

Now let’s test our WeatherForecastController API endpoint and take full advantage of OData 8.0.

Select

The $selectcapability will allow us to shape the incoming data to return only the attributes we need from our entities. In our case here, a WeatherForecastmodel has a Summaryattribute that we want to return and nothing else, here goes:

GET https://localhost:5001/WeatherForecast?$select=Summary

The results should be:

[
    {
        "Summary": "Freezing"
    },
    {
        "Summary": "Bracing"
    },
    {
        "Summary": "Cool"
    },
    {
        "Summary": "Hot"
    },
    {
        "Summary": "Mild"
    }
]

Filtering

The $filtercapbility allows us to search and only find entities that match a particular search criteria. In our case here, we want to return only weather forecasts that have a summary of Freezing as follows:

GET https://localhost:5001/WeatherForecast?$filter=Summary eq 'Freezing'

The results would look something like the following:

[
    {
        "date": "2021-07-13T23:20:18.9825999-07:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Freezing"
    }
]
Order By

Now, let’s experiment with the ordering capability – in this example, we will be ordering by the TemperatureC attribute in an ascending order as follows:

GET https://localhost:5001/WeatherForecast?$orderby=TemperatureC

The results would look something like the following:

[
    {
        "date": "2021-07-13T23:22:56.3856109-07:00",
        "temperatureC": -14,
        "temperatureF": 7,
        "summary": "Scorching"
    },
    {
        "date": "2021-07-15T23:22:56.3856117-07:00",
        "temperatureC": 1,
        "temperatureF": 33,
        "summary": "Freezing"
    },
    {
        "date": "2021-07-12T23:22:56.3856104-07:00",
        "temperatureC": 7,
        "temperatureF": 44,
        "summary": "Bracing"
    },
    {
        "date": "2021-07-14T23:22:56.3856113-07:00",
        "temperatureC": 33,
        "temperatureF": 91,
        "summary": "Hot"
    },
    {
        "date": "2021-07-11T23:22:56.3856049-07:00",
        "temperatureC": 34,
        "temperatureF": 93,
        "summary": "Balmy"
    }
]
Other Powers

OData also powers up your API with more capabilities such as navigation or $expand which allows your API consumers to navigate and expand existing entities to their related entities. There are also capabilities such as $count and $MaxTop which allows your API consumers to paginate and get a count of the entities returned per page.

 

The Future of OData

Currently the OData team and I are researching an revolutionary change to OData. Something I call OData NxT. The goal is reconceptualize OData by making it more modular, technology-agnostic and transcendable! Which I will be discussing more in future articles as we evolve our understanding of what OData consumers need and how we can support a scalable, modular, extensible future for OData. You can follow up the latest and greatest updates on OData in this github issue.

 

Final Notes

  1. There are so many new breaking changes to OData 8 which you can find documented and easy to try with Sam Xu’s conclusive article here.
  2. The new implementation of OData makes querying case-sensitive – $select=Summary is different from $select=summary
  3. You may experience a conflict with newer versions of Newtonsoft for your JSON serialization – we will talk about that in a different article.
  4. Enabling $count requires the EDM approach which is slightly different than the simple approach we followed here in this article.
  5. Here’s a sample project for the demo we’ve done above in this article – you can find it here.
  6. Here’s also a step-by-step walk through video to perform the same capabilities we talked about in this article – you can find the video here.

9 comments

Comments are closed. Login to edit/delete your existing comments

  • Hakan

    Thanks for the great article, I did not use OData before and a lot of friends suggested it to me with very high recommendations, I also really like the ease of configuration so much, this is very important to get new people to start using OData.

    I just want to point out that, I think, there is a typo in the Controller section, it said
    “simply add the good old EnableOData decoration to your controller” but the name of the attribute in the code below it is “EnableQuery”

    Again thank you for this great article and great technology

  • Joris Kommeren

    Great stuff.

    Do you have any information on when we can put Direct Query (query pushdown) to use in PowerBI for OData sources? In my mind it would be a marvelous addition to put the strengths of OData to good use! I’ve been asking for this for ages! Or do you think there’d be a technical limitation?

  • Lohith GN

    Great article. Great work that the OData team is putting in. Kudos to you all. I still remember the days of datajs – I was very excited about OData & datajs and just spoke & wrote about OData – 10 years ago 🙂

    Quick question: Is the team thinking about supporting OData in Azure Functions framework. Currently most of my projects – we tend to go with Azure Functions for HTTP API creation because it’s quick to create, easy to deploy, and economical. So if the OData SDK is made available for Azure Functions, I think it will be a great addition. Thoughts ??

  • Norm

    Great post. I have not used OData, but your post, and especially your YouTube video that you link to, make things very understandable. They likewise demonstrate how easy it will be to configure an ASP.NET Core Web API application to use OData. Both the post and the video motivate me to look into OData more deeply. Thanks.

  • hamed vojdani

    Great job but what is the workaround for this.

    “The new implementation of OData makes querying case-sensitive – $select=Summary is different from $select=summary”

    it is a vital need ,
    have recently switched to version 8
    i need to set Resolver.EnableCaseInsensitive to true
    ODataOptions does not have EnableCaseInsensitive flag

  • David p

    Awesome. I have just one word for you: SWAGGER!

    Compatibility with swagger has been held up by odata/asp.net, not the swashbuckle team. So, uh…. yeah.

  • Muhammad Afzal Qureshi

    Does the OData team have a plan to define routes without Controller class something similar to minimal API features in .NET 6?

    Eg.

    app.Map