Experimenting with OData in ASP.NET Core 3.1

Hassan Habib

Hassan

A lot of developers have asked me recently about OData compatibility with ASP.NET Core 3.0 and again with .NET Core 3.1 after it’s very recent release.

This demand became more and more critical with the recent announcement from the .NET team around .NET Core 2.2 reaching the end of its life on Dec 23rd of this year.

And because of all of that, the OData team at Microsoft have been working diligently in the last few months to ensure a stable release of OData that supports .NET Core 3.1 makes it out to the public as soon as possible.

And while the final release might take a bit longer to be production-ready, the OData team has recently released a beta version for developers to experiment with it, learn about it’s capabilities and possibly build some demo APIs and leverage it in some POCs.

In this article, I’m going to show you how you can build a modern ASP.NET Core 3.1 API with OData by simply following very few simple steps.

 

Prerequisites

In order for you to be able to create this demo on your local machine, you want to make sure that you have Visual Studio 2019 version 16.4 or later so you can leverage the capabilities of .NET Core 3.1, if you install that particular version of VS 2019 you will not need to install .NET Core 3.1 separately as it comes with the bundle.

You can check the current version of your Visual Studio 2019 by going to top menu, then Help then About Visual Studio as shows in the following screenshots:

If your current version of Visual Studio 2019 is lower than 16.4, you can upgrade your Visual Studio instance by clicking on the bell icon at the lower right corner of your Visual Studio instance then selecting to upgrade your Visual Studio as shows in the following screenshots:

Once you click the “More Details” link, it usually takes about 10 seconds and then you should be prompt with a dialog to upgrade your Visual Studio instance as follows:

Please make sure you save all your work before you click the “Update” button as the process will require Visual Studio to close automatically, you will not be prompted to save your work before Visual Studio closes, you also want to make sure you have Admin permissions to be able to continue with that process.

Once the upgrade is done, now you are ready to build ASP.NET Core applications with .NET Core 3.1, let’s talk about setting your project up.

 

Setting Things Up

For starters, let’s create a new ASP.NET Core Web Application by either starting a new instance of Visual Studio or simply going to File -> New -> Project, you should be then prompted with the following dialog:

After selecting ASP.NET Core Web Application (with C#) click the Next button you will be prompted to create a new name for your project and then selecting the version and template of which your project should be based on as follows:

 

 

Please make sure you select ASP.NET Core 3.1 from the drop down menu at the top right side, and API as a template for your project then click “Create“.

 

Installing OData

Now that you have created a new project, let’s go ahead and install the beta release of OData for ASP.NET Core 3.1

There are two ways you can install the beta library depends on your preference, if you are a command line kind of developer, you can simply open the package manager console by clicking on the Tools top menu option, then Nuget Package Manager then Package Manager Console as follows:

you will be prompted with a console window so you can type the following command:

If you don’t like using command lines, you can simply install the very same package by going to the exact same menu options we selected above, except you are going to choose Manage Nuget Packages for Solution instead of Package Manager Console the following dialog will appear so you can install the library as follows:

There are few things that I have highlighted in that screenshot that you need to pay attention to:

  1. You must check the “Include prerelease” so you can see the beta release of the nuget package.
  2. Search for Microsoft.AspNetCore.OData and select the first option.
  3. Select the project in which you want to install your library, in our case here since we have one project, it’s safe to just check the entire project.
  4. Make sure you select Latest prerelease 7.3.0-beta in the drop down menu on the right side before you click the Install button.

 

Models & Controllers

Now that we have OData installed, let’s create a Student model and create a controller to return a list of students as follows:

Now let’s create a simple API controller that returns a list of students:

Please notice that this controller is only created this way for a demo purpose, ideally your controller should return an IQueryable to achieve better performance and execute queries on your database server if you are retrieving your data from a database.

 

Final Step

Our final step here is to modify the startup.cs file to support OData, our code here will be very similar to our code from previous articles, let’s start with the ConfigureServices method in our startup.cs file as follows:

You will notice a couple of changes in the above code, Adding OData which is just as similar as any other OData powered application.

The second change is disabling endpoint routing, let’s talk about that for a bit.

For starters, this is not an ideal situation, the final release of OData shall allow endpoint routing while supporting OData queries.

But for those who want to understand what endpoint routing setting is, especially for .NET Core 3.0 and above, here’s a quote from a previous post for Daniel Roth:

In ASP.NET Core 2.2 we introduced a new routing implementation called Endpoint Routing which replaces IRouter-based routing for ASP.NET Core MVC. In the upcoming 3.0 release Endpoint Routing will become central to the ASP.NET Core middleware programming model. Endpoint Routing is designed to support greater interoperability between frameworks that need routing (MVC, gRPC, SignalR, and more …) and middleware that want to understand the decisions made by routing (localization, authorization, CORS, and more …).

While it’s still possible to use the old UseMvc() or UseRouter() middleware in a 3.0 application, we recommend that every application migrate to Endpoint Routing if possible. We are taking steps to address compatibility bugs and fill in previously unsupported scenarios. We welcome your feedback about what features are missing or anything else that’s not great about routing in this preview release.

And while endpoint routing is one of the most important upgrades to ASP.NET Core 3.0, with this beta release you could still leverage the power of OData without leveraging endpoint routing temporarily.

With that being said, let’s move on to the next step which is implementing a GetEdmModel method as we have done previously and change the routing implementing in the Configure method as follows:

 

I have intentionally left the app.UseEndPoints to show you what code you need to remove (again, temporarily for this beta release) and what code you need to add to leverage the power of OData.
And that should be the final step in this tutorial, now you can run you application and call your endpoint as follows:

and the results should be as follows:

 

 

Final Notes

  1. Huge thanks to Sam Xu, Saurabh Madan and the the rest of the OData team on the great efforts they have made to produce this beta release, and as you are reading this article, the team continues to push improvements and features before announcing the final release of OData 7.3.0 for ASP.NET Core 3.1 which should have a long term support of 3 years.
  2. This beta release should not be used in any way shape or form for production environments, it’s mainly for POCs and demos.
  3. OData team should announce the final release of OData for .NET Core 3.1 sometime in the second quarter of 2020.
  4. You can follow up on the most recent updates for OData on this public github repository and this thread as well.
  5. This is a repository for the demo in this article.

If you have any questions, comments, concerns or if you are running into any issues running this demo feel free to reach out on this blog post, we are more than happy to listen to your feedback and communicate your concerns.

 

Update

  1. Just a couple of days ago, OData team has released the final version of OData 7.3.0 to support .NET Core 3.1 you can find the package in here.
  2. OData team is working very closely with the .NET team to address the endpoint routing issue, we will announce the changes as soon as they become ready.
  3. You can now use OData in your production environment as it passed it’s beta stage and is now ready for production-ready applications.

 

27 comments

Comments are closed.

  • Avatar
    Shimmy Weitzhandler

    Thank you Hassan!
    The effort Microsoft put recently in OData is really a great step forward and really appreciated.

    I wish this effort would also spread to client side OData management.
    Right now, the only .NET client-side OData option is Simple.OData.Client which lacks of low maintenance and lack of support for modern techniques such as IoC/DI, IHttpClientFactory, and others.

    Thanks!

  • Mahmut Jomaa
    Mahmut Jomaa

    Thank you for all the efforts.

    There is actually something I never found out. Is it possible in OData to ignore extra properties on a POST request? Currently it will send a bad request. I know that you can use dynamic properties, but I want to ignore (not use or save) all extra properties of a request. Maybe it is not the right place to ask 🙂

  • Avatar
    Onur Omer OZTURK

    It is good to get selective properties with OData but it makes no great difference/performance gain without passing this selection to data layer. The only gain will be in data size and only between client and the server. Ability to pass this selection to the data layer is provided with EF (I mean IQueryable) but EF is like using anti-biotics, takes more than it brings in the long run.

    Thanks for the OData introduction anyway, I will be using it with a custom ORM, happy to see it in action for .NetCore 3.1.

  • ivan zinov
    ivan zinov

    My company created an API that is running on .NET Core 2.2 and it is using the OData package. The dilemma here is that we are not yet in production because VMs for production should be created. Also, Microsoft made the announcement that 2.2 is not going to be supported anymore. In addition to that, my IT department is not willing to install 2.2 on production servers.
    We can do the upgrade of the API to 3.1, but you said your team is not ready yet to be fully compatible with 3.1.
    Please advice how I can proceed.
    Thanks in advance

  • ivan zinov
    ivan zinov

    Is endpoint routing implemented on your final update? or do I need to implement IODataRoutingConvention? Not having this creates an incompatibility with other middlewares that are available on .netcore like HealChecks that needs to be registered through the IEndPointRouterBuilder.

    app.UseEndpoints(endpoints =>
    {
    endpoints.MapHealthChecks(“/healthz”).RequireHost(“*:8080”);
    });

    And having both UseEndpoints and UseMvc is basically a nightmare. I posted the question here as well:
    https://stackoverflow.com/questions/59741591/how-to-register-odata-extension-methods-in-netcore-3-1-outside-of-usemvc-middle/59746510#59746510

  • Avatar
    Chris Smith

    Odata looks great! We have one question though.
    Is it possible to pass the ODataQueryOptions to lower layers. We’re using micro services with MassTransit and want to pass the filter down to the appropriate micro service so it only returns the required data in the query rather than everything then the API filtering the data. We can’t return IQueryable from the micro service. Any way of dealing with this issue?

  • Avatar
    Denny Figuerres

    I have OData seeming to work but my results are not including the metadata and i am not sure why.
    seems like it’s just returning normal json data the data is valid just no metadata — so i am not getting next link, row count etc…
    trying to fix it but not sure where to make a change for it ….

    UPDATE: it looks like there is something going on with asp.net core routing and how OData gets hooked up.
    if the controllers are using controllerbase with a route attribue like “data” and the startup routename and prefix are “odata” then it’s like the controllers are routed 2 times one time as a webapi that is queryable but will not return metadata and another time that is a true odata endpoint….
    if they are not done that way then it seems that i can only access the webapi version without the metadata.
    i bet this has to do with the changes in the routing code and the use of the UseMvc / UseEndpoints mapping options but i am not deep into what they are doig to that code….

    it would be great if we can get some clarity on how to setup the routing to work 100% and not have blind holes that do strange things….

  • Avatar
    Patrick Lee

    Unfortunately this post is not working for me. It also seems to contain some errors, e.g. the instruction to call the endpoint refers to /odata/students but the controller code shows [Route(“api/[controller]”)], with api rather than odata. And the article doesn’t say how to get the IEdmModel GetEdmModel() part of the Startup.cs code to build: I got this to build via adding the following using statements (but no idea if these are the correct ones – the article should say)

    using Microsoft.OData.Edm;
    using Microsoft.AspNet.OData.Builder;

    But the main problem is that (as too often with Microsoft’s dot net core examples), *getting the code to work is a very painful process*, involving getting lots of errors, having to search for solutions, thinking that you (the developer) has done something wrong, before concluding that, despite the articles implying that new versions are ready for use (e.g. AspNetCore.OData version 7.3.0 has been released), the articles/documentation is incomplete and buggy!

    Following the instructions as written in this example (and correcting the controller code to have odata in the route rather than api), just gives error 404, page not found for either /odata/students or /odata/students?$select=name.

    This is extremely frustrating, and frankly very poor.

    PS The “Stay informed” link to Twitter for this OData page is to @odataorg where the most recent tweet is from 2015! Again, very poor.

    • Hassan Habib
      Hassan Habib

      Hi Patrick,
      Thanks for pointing out the error in the post, I have fixed the controller code, although and as you may have noticed cloning the referenced github repo it doesn’t really have much impact as OData overrides that annotation.
      Now, what I’m really wondering about is that whether the code I referenced in github works or not, please let us know, we’re happy to help.

  • José Miguel Rodrigues
    José Miguel Rodrigues

    Thanks for the tutorial, my company stack is in OpenApi, and I would love to use OData as a “better rest”, but the lack of oficial client generators like in OpenApi is a no go.

    Because in OpenApi you can generate a client in typescript, JavaScript, python, etc… On Odata no, and is limiting the evolution of this standart

  • Avatar
    Denny Figuerres

    this blob post uses the web api controller base, but when i look at
    Odata Webapi Sample
    it does not, it uses OData Controller — so which one is right ? the github sample or the blog post ?
    one of the reasons i am asking is due to some seemingly odd routing i see when i used the blog post sample code …. i have it working but in swagger the api endpoint shows up without the odata meta data. but if i use the /odata/ route that does not show up in swagger it mostly works but not the get(id) method.

    i am thinking i will have to re-do my code with the odata controller and re-test it …..

  • Avatar
    Luis Espinoza

    Thanks for your great article,

    I’m currently facing a problem, I am using OData with EF Core and AutoMapper and I already have the queries executed using projection, however when I use expand I only get the “[” symbol.

    If you could help me or make an example would be great.

    Thank you very much.