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
<PackageReference Include="Benevia.Core.API" Version="0.8.7" />
<PackageVersion Include="Benevia.Core.API" Version="0.8.7" />
<PackageReference Include="Benevia.Core.API" />
paket add Benevia.Core.API --version 0.8.7
#r "nuget: Benevia.Core.API, 0.8.7"
#:package Benevia.Core.API@0.8.7
#addin nuget:?package=Benevia.Core.API&version=0.8.7
#tool nuget:?package=Benevia.Core.API&version=0.8.7
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
$topand$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:
WebApplicationFactory<Program>creates a test server hosting your applicationCreateClient()provides an HTTP client configured to send requests to the test server- Requests are processed through the full API pipeline (routing, controllers, OData, database)
- 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 | Versions 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. |
-
net10.0
- Benevia.Core (>= 0.8.7)
- Benevia.Core.Annotations (>= 0.8.7)
- Benevia.Core.Generator (>= 0.8.7)
- Benevia.Core.Telemetry (>= 0.8.7)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.5)
- Microsoft.AspNetCore.Identity.EntityFrameworkCore (>= 10.0.5)
- Microsoft.AspNetCore.OData (>= 9.4.1)
- Microsoft.EntityFrameworkCore (>= 10.0.5)
- Microsoft.EntityFrameworkCore.Proxies (>= 10.0.5)
- Newtonsoft.Json (>= 13.0.4)
- Swashbuckle.AspNetCore (>= 10.1.5)
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 |