Benevia.Core.API 0.8.7

dotnet add package Benevia.Core.API --version 0.8.7
                    
NuGet\Install-Package Benevia.Core.API -Version 0.8.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Benevia.Core.API" Version="0.8.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Benevia.Core.API" Version="0.8.7" />
                    
Directory.Packages.props
<PackageReference Include="Benevia.Core.API" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Benevia.Core.API --version 0.8.7
                    
#r "nuget: Benevia.Core.API, 0.8.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Benevia.Core.API@0.8.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Benevia.Core.API&version=0.8.7
                    
Install as a Cake Addin
#tool nuget:?package=Benevia.Core.API&version=0.8.7
                    
Install as a Cake Tool

Benevia.Core.API

Introduction

Benevia.Core.API provides RESTful OData API infrastructure for exposing entities through HTTP endpoints. It automatically generates CRUD endpoints for entities decorated with [ApiEntity], handles database access via Entity Framework, and supports rich OData querying capabilities.

Use this library when you need:

  • RESTful API with minimal boilerplate
  • OData query support (filtering, sorting, expansion, pagination). See
  • Multi-tenant database architecture
  • Integration with Entity Framework Core

Note: This library works standalone or integrates with Benevia.Core.Events for business logic on entities.

Getting Started

1. Install the NuGet package

dotnet add package Benevia.Core.API

2. Create your model

Entities can be simple POCOs only decorated with [ApiEntity]. Use Data Annotations to provide Entity Framework with the needed db info.

namespace MyApp.Model;

[ApiEntity]
[NaturalKey(nameof(Product.Sku))]
public partial class Product : EntityBase
{
    [Required]
    [MaxLength(20)]
    public partial string Sku { get; set; }

    public partial string Description { get; set; }

    public partial decimal Price { get; set; }

    public partial decimal StockQuantity { get; set; }
}

3. Add & use the model & endpoints

In your Program.cs:

// ...

builder.Services
    .AddMyAppModel()     //generated extension from your model
    .AddMyAppEndpoints() //generated extension from your model
    .AddCoreApi((o, t) => o.UseNpgsql(t?.ConnectionString));

// ...

app.UseCoreApi();
app.Run();

// ...

4. Set up configuration

Add tenant and authentication configuration to your appsettings.Development.json:

{
  "Tenants": {
    "Demo": {
      "ConnectionString": "Host=localhost;Database=demo_benevia_erp;Username=postgres;Password=postgres",
      "EncryptionKey": "e8a916b18c496995374f11beb0922b5231093e1c9ca0f31b34d63edafb25b10c"
    }
  },
  "JWT": {
    "Issuer": "yourcompany",
    "Audience": "yourcompany",
    "AccessTokenExpirationHours": 0.5,
    "RefreshTokenExpirationDays": 14
  }
}

JWT settings provided in API by default, but If you add your own JWT configuration section, make sure you pass it in Program.cs so it overwrites defaults:

.AddCoreApiEvents((o, t) => o.UseNpgsql(t?.ConnectionString), 
    jwtOptions: _ => builder.Configuration.GetSection("JWT").Get<JwtOptions>())

Production deployment:
For production environments, use environment variables instead of storing secrets in configuration files. The application uses .NET's IConfiguration, which automatically reads from environment variables and more. Example:

Tenants__Demo__ConnectionString="Host=prod-db;Database=erp;Username=app;Password=***"
Tenants__Demo__EncryptionKey="***"

Feel free to use a different Entity Framework database provider (such as Microsoft SQL, SQLite, etc).

5. Configure API Options (Optional)

You can customize API behavior through the ApiOptions section in your configuration:

{
  "ApiOptions": {
    "EnableLowerCamelCase": true,
    "MaxTop": 500,
    "MaxNodeCount": 100,
    "MaxExpansionDepth": 5
  }
}
Option Default Description
EnableLowerCamelCase false When true, OData JSON responses use camelCase property names (e.g., unitPrice). When false, uses PascalCase (e.g., UnitPrice).
MaxTop 500 Maximum number of items returned by a single query using $top.
MaxNodeCount 100 Maximum number of nodes allowed in a query.
MaxExpansionDepth 5 Maximum depth for $expand operations.

Note: Unlike standard ASP.NET Core JSON options, OData uses its own Entity Data Model (EDM) for serialization. The EnableLowerCamelCase option configures the EDM builder directly to ensure consistent casing across all OData responses.

Using the API

The Benevia.Core.API package automatically exposes your entities as OData RESTful endpoints. OData (Open Data Protocol) is a standardized protocol for building and consuming RESTful APIs, providing rich querying capabilities.

What is OData?

OData allows clients to:

  • Filter data with $filter (e.g., ?$filter=Price gt 100)
  • Sort results with $orderby (e.g., ?$orderby=Name desc)
  • Select specific fields with $select (e.g., ?$select=Sku,Description)
  • Expand related entities with $expand (e.g., ?$expand=Category)
  • Paginate with $top and $skip (e.g., ?$top=10&$skip=20)
  • Count results with $count (e.g., ?$count=true)

For full OData syntax, see the OData documentation.

CRUD Operations

Each entity decorated with [ApiEntity] gets a full CRUD API:

Create (POST)
POST /api/Products
Content-Type: application/json

{
  "Sku": "PROD-001",
  "Description": "Premium Widget",
  "Price": 29.99,
  "StockQuantity": 100
}
Read All (GET)
GET /api/Products
Read One (GET by Key)
GET /api/Products(123e4567-e89b-12d3-a456-426614174000)
Update (PATCH)
PATCH /api/Products(123e4567-e89b-12d3-a456-426614174000)
Content-Type: application/json

{
  "Price": 24.99,
  "StockQuantity": 85
}
Delete (DELETE)
DELETE /api/Products(123e4567-e89b-12d3-a456-426614174000)

Calling c# methods (Functions and Actions)

Methods can be created in c# and automatically be exposed to the OData API. Methods are defined in your c# class in this way:

See Core.Events documentation

Query Examples

Filter by price:

GET /api/Products?$filter=Price gt 20 and Price lt 50

Sort by SKU descending:

GET /api/Products?$orderby=Sku desc

Get only specific fields:

GET /api/Products?$select=Sku,Description,Price

Combine multiple queries:

GET /api/Products?$filter=StockQuantity gt 0&$orderby=Price&$top=10

Expand related entities (if you have navigation properties):

GET /api/Products?$expand=Category,Supplier

Count results:

GET /api/Products?$count=true&$filter=Price lt 100

Authentication

The API uses JWT (JSON Web Token) authentication for securing endpoints.

Sign In

POST /api/auth/signin
Content-Type: application/json

{
  "TenantId": "Demo",
  "Username": "myuser",
  "Password": "MyPassword@123"
}

Returns an access token and refresh token. Include the access token in the Authorization header for all API requests:

GET /api/Products
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Token Refresh

When the access token expires (default: 30 minutes), use the refresh token to get a new one:

POST /api/auth/refresh
Content-Type: application/json

{
  "RefreshToken": "your-refresh-token-here"
}

Note: Refresh tokens are one-time use only and expire after 14 days. Always use the new refresh token returned in each response.

Personal Access Tokens (PAT)

For third-party integrations (e.g., PowerBI, scripts) that cannot perform the interactive login flow, you can generate a long-lived Personal Access Token (PAT).

Endpoint: POST /api/auth/pat Auth Required: Yes (Bearer Token)

POST /api/auth/pat
Authorization: Bearer <your-current-access-token>
Content-Type: application/json

{
  "expirationDays": 90
}
  • expirationDays: Required. Must be between 1 and 365 days.

Returns a long-lived JWT access token. Note that these tokens are stateless and cannot be revoked individually without rotating the tenant's signing key.

Basic Authentication with PAT

Some OData clients (like Excel or PowerBI) may not support Bearer token authentication easily. For these scenarios, the API supports Basic Authentication using your PAT.

Username: pat Password: <your-pat-token>

Example header: Authorization: Basic <base64-encoded-credentials>

Where credentials are pat:your-long-jwt-token.

Integration Testing

Benevia.Core.API works seamlessly with ASP.NET Core's WebApplicationFactory for integration testing. This allows you to test your API endpoints with a real HTTP client and database.

What's happening:

  1. WebApplicationFactory<Program> creates a test server hosting your application
  2. CreateClient() provides an HTTP client configured to send requests to the test server
  3. Requests are processed through the full API pipeline (routing, controllers, OData, database)
  4. You can use an in-memory database or test database for isolation
using Microsoft.AspNetCore.Mvc.Testing;
using System.Net.Http.Json;
using Xunit;

public class ProductApiTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;
    
    public ProductApiTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
        await AuthenticateClient(_client);
    }
    
    [Fact]
    public async Task CreateProduct_ReturnsCreatedProduct()
    {
        // Arrange
        var product = new { Name = "Test Product", Price = 19.99 };
        
        // Act
        var response = await _client.PostAsJsonAsync("/api/Products", product);
        
        // Assert
        response.EnsureSuccessStatusCode();
        var created = await response.Content.ReadFromJsonAsync<Product>();
        Assert.Equal("Test Product", created.Name);
    }
}

More Info

For more information about the architecture of Benevia.Core.API, see ./ARCHITECTURE.md.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on Benevia.Core.API:

Package Downloads
Benevia.Core.DataGenerator

Benevia Core DataGenerator library for generating test and sample data.

Benevia.Core.Blobs

Benevia Core Blobs library with Azure Blob Storage integration for file and blob management.

Benevia.Core.API.Events

Benevia Core API Events integration library combining API features with event-driven architecture.

Benevia.Core.API.Postgres

Benevia Core API PostgreSQL integration library combining API features with PostgreSQL database support.

Benevia.Core.API.Workflows

Benevia Core API Workflows library for workflow and business process automation.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.8.7 86 4/2/2026
0.8.7-ci.46 40 4/2/2026
0.8.7-ci.45 38 4/2/2026
0.8.7-ci.44 41 4/1/2026
0.8.7-ci.43 40 3/31/2026
0.8.7-ci.42 36 3/31/2026
0.8.6 216 3/25/2026
0.8.6-ci.40 46 3/25/2026
0.8.5 143 3/25/2026
0.8.5-ci.38 40 3/25/2026
0.8.5-ci.37 44 3/25/2026
0.8.5-ci.36 41 3/24/2026
0.8.4 236 3/23/2026
0.8.4-ci.34 43 3/23/2026
0.8.4-ci.33 40 3/23/2026
0.8.3 170 3/19/2026
0.8.3-ci.31 46 3/19/2026
0.8.3-ci.30 57 3/19/2026
0.8.3-ci.29 44 3/19/2026
0.8.3-ci.28 47 3/19/2026
Loading failed