ASP.NET Core OData Documentation

repository·main·Indexed 19 days ago

https://github.com/odata/aspnetcoreodata

A server-side library for building OData services on top of ASP.NET Core. It provides features for routing, query handling, model building, and formatters via the Microsoft.AspNetCore.OData NuGet package. The library supports OData controllers with [EnableQuery], Minimal APIs, dynamic EDM model creation, and advanced querying capabilities including alternate keys (Core and Community terms), composite keys, and standard OData query options like $expand, $select, $top, and $orderby.

Tokens
8.3K
Snippets
32
Records
42
Agent score
68%

What's inside ASP.NET Core OData

  1. How OData routing conventions work

    main

    OData routing matches your Entity Data Model (Edm Model) to your ASP.NET Core controllers using one of two conventions:

    1. Convention Routing (Default): Routes are discovered based on naming conventions. For example, an entity set named Customers expects a controller named CustomersController. If you rename the controller (e.g., to MyCustomersController), OData will no longer match the Customers entity set.
    2. Attribute Routing: Routes are discovered based on attributes applied directly to the controller class or its methods.

    By default, the project uses Convention Routing.

  2. How Alternate Keys work in ASP.NET Core OData

    main

    An Alternate Key is a secondary identifier for an entity that is distinct from its declared primary key. In ASP.NET Core OData 8.x, you can define these using vocabulary annotations in your metadata.

    There are two ways to define them:

    1. Recommended: Use the Org.OData.Core.V1.AlternateKey term.
    2. Backward Compatible: Use the OData.Community.Keys.V1.AlternateKeys term.

    To invoke an API using an alternate key, you must use the alternateKeyAlias=alternateKeyValue pattern, which is only supported when using attribute routing.

  3. Use Non-Edm models in OData

    main

    A Non-Edm model refers to a route that does not have an explicit Entity Data Model (EDM) configured. Even without an EDM, you can still perform OData queries such as $select and $top on these routes.

    Example Request: http://localhost:5000/api/accounts?$select=Name&$top=3

    Example Response:

    [
        {
            "Name": "Warm"
        },
        {
            "Name": "Scorching"
        },
        {
            "Name": "Sweltering"
        }
    ]

    Known Limitation: There are currently known issues when attempting complex property selection on Non-Edm models, such as selecting nested properties:

    • ?$select=HomeAddress
    • ?$select=HomeAddress($select=City)
    http://localhost:5000/api/accounts?$select=Name&$top=3
  4. Enable camelCase property names in OData $select queries

    main

    In non-Edm OData scenarios, using the $select query parameter causes the response to return selected properties as keys within a dictionary. By default, these dictionary keys use the original C# property names (PascalCase) rather than the camelCase used in standard JSON responses.

    To ensure that $select results use camelCase for property names, you must configure the DictionaryKeyPolicy for the JSON serializer in your ASP.NET Core service configuration.

    builder.Services.AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
        })
        .AddOData(options => options.Select().Filter().OrderBy());
  5. Configure OData Query Request middleware

    main

    To handle OData queries where the query options are passed in the request body instead of the URL, use the UseODataQueryRequest() extension method. This is useful for avoiding URL length limitations by appending /$query to the resource path and using the POST verb.

    Important: This middleware must be added to the pipeline before app.UseRouting().

    app.UseODataQueryRequest();
  6. Implement Route Versioning with multiple OData APIs

    main

    To support multiple versions of an API (e.g., v1 and v2) hosted at different prefixes, follow these steps:

    1. Call AddRouteComponents multiple times in ConfigureServices, once for each version/prefix and its corresponding Edm Model.
    2. Decorate the controllers for each version with the [ODataRouteComponent("prefix")] attribute to tell OData which versioned component the controller belongs to.

    Note: Controllers intended for OData should inherit from ODataController.

    // 1. Setup in Startup.cs
    services.AddControllers()
                .AddOData(opt => opt.AddRouteComponents("v1", GetEdmModel()))
                .AddOData(opt => opt.AddRouteComponents("v2", GetEdmModel2()));
    
    // 2. Decorate Controllers
    [ODataRouteComponent("v1")]
    public class CustomersController : ODataController
    {
        // v1 logic
    }
    
    [ODataRouteComponent("v2")]
    public class CustomersController : ODataController
    {
        // v2 logic
    }
  7. Perform CRUD operations on OData entities

    main

    The sample demonstrates full CRUD (Create, Read, Update, Delete) capabilities for the students resource under the odata route group:

    • Read (GET): Retrieve a list of students or specific properties using $select.
    • Create (POST): Send a JSON body to the collection endpoint to add a new entity.
    • Update (PATCH): Send a JSON body to a specific entity URI (e.g., /odata/students/10) to perform a partial update. This can also be used to update foreign keys (e.g., changing a schoolId to move a student to a different school).
    • Delete (DELETE): Remove an entity by its ID via the specific entity URI.
    // POST /odata/students
    {
        "firstName": "Sokuda",
        "lastName": "Yu",
        "favoriteSport": "Soccer",
        "grade": 7,
        "schoolId": 3,
        "birthDay": "1977-11-04"
    }
    
    // PATCH /odata/students/10
    {
        "firstName": "Sokuda",
        "lastName": "Yu",
        "schoolId": 4
    }
  8. Query using composite alternate keys

    main

    Composite alternate keys allow you to identify an entity using a combination of multiple properties. This is useful when a single property is not unique, but a set of properties is.

    Example for a Person entity using a composite key of CountryOrRegion and Passport:

    • Community Composite: ~/odata/People(c_or_r='USA',passport='9999')
    • Core Composite: ~/odata/People(core_c_r='USA',core_passport='9999')
  9. Configure OData Route Debug middleware

    main

    To enable debug routing that lists all available endpoints in your service, use the UseODataRouteDebug() extension method. This provides a /$odata endpoint for easy debugging.

    Important: This middleware must be added to the pipeline before app.UseRouting().

    app.UseODataRouteDebug();