Skip to content

Feature: Implement ASP.NET Core OData v8 with Swagger/OpenAPI #1157

@PoulSteffensen

Description

@PoulSteffensen

Summary
Integrate ASP.NET Core OData v8 into the Web API project of dotnet-starter-kit and expose OData endpoints through Swagger/OpenAPI. This gives clients rich, standardized query capabilities ($filter, $select, $expand, $orderby, $top, $skip, $count) while keeping our API surface minimal and discoverable via Swagger UI. Implementation follows Microsoft's OData guidance and Swashbuckle setup for ASP.NET Core.


Why this belongs in dotnet-starter-kit

  • Powerful querying with fewer endpoints: Built-in OData query options reduce the need for custom endpoints and fit admin/back-office/reporting scenarios.
  • Modern, supported stack: ASP.NET Core OData v8 is actively maintained; OData .NET 8 modernizes internals on recent .NET versions.
  • Discoverability via Swagger/OpenAPI: Swashbuckle provides interactive docs; newer ASP.NET Core templates require explicit OpenAPI/Swagger configuration.

References


Scope (for this repository)

Projects/paths
Assume the Web API entry point is src/apps/webapi/Program.cs. We’ll update docs if paths differ.

  1. Add OData package

    • Add Microsoft.AspNetCore.OData to the Web API project.
  2. Register OData services & EDM

    • Build an EDM model (ODataConventionModelBuilder) and register route components under /odata.
    • Enable query options: .Select().Filter().OrderBy().Expand().Count().SetMaxTop(null).
  3. Create sample controller(s)

    • Inherit from ODataController and annotate GET actions with [EnableQuery].
  4. Wire up Swagger/OpenAPI

    • Add Swashbuckle packages, then AddSwaggerGen(), UseSwagger(), UseSwaggerUI() in Program.cs.
    • Confirm OData endpoints operate and Swagger loads without formatter conflicts (workarounds exist if needed).
  5. Documentation

    • Update kit docs (e.g., /docs or README) with examples & screenshots:
      • GET /odata/Products?$filter=Price gt 20
      • GET /odata/Products?$select=Id,Name&$orderby=Name
      • GET /odata/Products?$expand=Category&$count=true

Proposed Implementation (starter-kit aligned)

src/apps/webapi/Program.cs (illustrative—adapt to actual path/namespaces)

using Microsoft.AspNetCore.OData;
using Microsoft.OData.ModelBuilder;

var builder = WebApplication.CreateBuilder(args);

// Swagger / OpenAPI
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// OData EDM
var odataModelBuilder = new ODataConventionModelBuilder();
// Replace with a real entity from the kit (e.g., Products, Tenants, Users)
odataModelBuilder.EntitySet<Product>("Products");

builder.Services
    .AddControllers()
    .AddOData(opt => opt
        .Select().Filter().OrderBy().Expand().Count().SetMaxTop(null)
        .AddRouteComponents("odata", odataModelBuilder.GetEdmModel()));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
    // Optional: app.UseODataRouteDebug(); // exposes ~/$odata routing page
}

app.UseRouting();
// keep existing auth/tenant middleware as-is
app.MapControllers();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions