OData with Web Api .NET 7

In Dotnet
Tags #c #odata #aspnet #webapi #net
Published 12/29/2022

OData is the standard protocol that allows access to the RESTful APIs in the sample and standard way. The benefit of OData is providing create, read, update, and delete operations via web technologies to provide access to information from API.

Why do I have this blog?

In the couple of months ago, I had the chance to develop the OData API for feeding data for the clients. In this blog, I'm going to talk about the OData (Open Data Protocol) technology that was initiated by Microsoft in 2007.

What's OData?

OData is the standard protocol that allows access to the RESTful APIs in the sample and standard way. The benefit of OData is providing create, read, update, and delete operations via web technologies to provide access to information from API.

Getting Started the OData

The main feature of OData that I going to talk about in this blog are:

  • CRUD supported through HTTP verb for GET, POST, PATCH, and DELETE.
  • Query option through HTTP request
    • Filter
    • Count
    • Select
    • Orderby
    • Skip
    • Top
    • Expand

Prerequisites

  • Visual Studio 2022 with the ASP.NET and web development
  • .NET 7 SDK

Create a project from scratch

Target a new project with ASP.NET Core Web API template and in the additional option Use controllers.

Screenshot_2022-12-10_023434.jpg

Add Microsoft.AspNetCore.OData

Install Package:

Install-Package Microsoft.AspNetCore.OData

or use dotnet-cli

dotnet add package Microsoft.AspNetCore.OData

Define data model

using System.ComponentModel.DataAnnotations;

namespace DemoOData;

public class Product
{
    [Key]
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
}

Add EntityFramework with model

Install-Package Microsoft.EntityFrameworkCore

or use dotnet-cli

dotnet add package Microsoft.EntityFrameworkCore

Create a DbContext

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> dbContextOptions)
        : base(dbContextOptions) { }

    public DbSet<Product> Products { get; set; }
}

Create an OData EDM Model from Entity Model

EDM is an entity data model to map between the any data source format and the OData engine. For more detail and example on how to create EDM, check out OData model builders and Basic EDM Creation

static IEdmModel GetEdmModel()
{
    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntitySet<Product>(nameof(Product));
    return modelBuilder.GetEdmModel();
}

Add Dependencies to the ASP.NET Service Collection

Add OData service after API controller and specify OData route and register EDM model.

builder.Services.AddControllers()
    .AddOData(options => options
        .AddRouteComponents(routePrefix: "odata", model: GetEdmModel()));

Configure OData query features

builder.Services.AddControllers()
    .AddOData(options => options
        .AddRouteComponents(routePrefix: "odata", model: GetEdmModel())
        .Select()
        .Filter()
        .OrderBy()
        .Count());

or enable all query features by

builder.Services.AddControllers()
    .AddOData(options => options
        .AddRouteComponents(routePrefix: "odata", model: GetEdmModel())
        .EnableQueryFeatures());

Create API Controller to support OData

Create API controller and inherit to ODataController and add CRUD operations.

public class ProductController : ODataController
{
    private readonly ApplicationDbContext _context;

    public ProductController(ApplicationDbContext context) => _context = context;

    [HttpGet]
    [EnableQuery(PageSize = 10)]
    public ActionResult<IQueryable<Product>> Get() 
        => Ok(_context.Products);

    [HttpGet]
    [EnableQuery]
    public async Task<ActionResult<Product?>> Get([FromODataUri] Guid key) 
        => Ok(await _context.Products.FindAsync(key));

    [HttpPost]
    [EnableQuery]
    public async Task<ActionResult<Product>> Post([FromBody] Product entity)
    {
        await _context.AddAsync(entity);
        await _context.SaveChangesAsync();
        return entity;
    }

    [HttpPatch]
    [EnableQuery]
    public async Task<ActionResult<Product>> Patch([FromODataUri] Guid key, Delta<Product> updatedEntity)
    {
        var product = await _context.Products.FindAsync(key);
        if (product is null) return NotFound();

        updatedEntity.Patch(product);
        await _context.SaveChangesAsync();
        return product;
    }

    [HttpDelete]
    [EnableQuery]
    public async Task<ActionResult> Delete([FromODataUri] Guid key)
    {
        await _context.Products.Where(x => x.Id == key).ExecuteDeleteAsync();
        return NoContent();
    }
}

Query data from OData API

Example GET from Odata route
https://localhost:7270/odata/Product

GETALL.jpg

Add filter and specified property to query
https://localhost:7270/odata/Product?$filter=Name eq 'Apple'&$select=Description

GetAllWithQuery.jpg


GET by key
https://localhost:7270/odata/Product(5ec0f998-358b-4f0a-bed2-3ab112fcb21c)

GetByKey.jpg

Example POST to create an object

POST.jpg


Example PATCH to updating object

For the patch is supporting partially update.

PATCH.jpg


Example DELETE to delete the object

Delete.jpg



Conclusion

For this blog is talking about how to build the RESTful API to supporting OData and show the key features of OData. but the OData have more features and also integration with any client that I going to talk about in next article.

Checkout sample code here : https://github.com/aixasz/SampleOData