A fully functional Native AOT implementation of FastEndpoints for .NET 10. This repo exist as iteration playground until the official fastendpoint repo becomes fully AOT compatible.
This has been a "guided" vibe coded implementation so do take care in checking details. My main aim was just to get it working therefor trimming on many libs have been disabled in the rd.xml file. Further iteration is needed to improve the code for production.
This project demonstrates how to run FastEndpoints with Native AOT compilation, achieving:
- ⚡ Not using JIT compilation at runtime
- 📦 Single-file deployment (~15MB self-contained executable)
- 🚀 Reduced memory footprint
- 🔒 Hopefully reduced cost for cloud service
- .NET 10 SDK
- Visual Studio Code
# Navigate to the project root
cd FastEndpointsAOT-main
# Run in development mode (JIT)
cd Web
dotnet run
# Publish as Native AOT (from project root)
cd Web
dotnet publish -c Release -o ../publishThe published executable will be in ./publish/Web.exe.
| Folder | Description |
|---|---|
Web/ |
Main API application with FastEndpoints |
Shared/ |
Shared DTOs, contracts, and HttpClient extensions |
ApiRequestGenerator/ |
Source generator for AOT-compatible API request metadata |
Tests/ |
Integration and unit tests |
Benchmark/ |
Performance benchmarks using BenchmarkDotNet and Bombardier |
Src/ |
FastEndpoints source (for reference/customization) |
The ApiRequestGenerator automatically scans your FastEndpoints and generates AOT-compatible metadata:
- Extracts routes and HTTP methods from
Configure()methods - Generates
IApiRequest<TSelf, TResponse>implementations with static JSON type info - Enables clean HttpClient usage without reflection
// Auto-generated: each request DTO knows its route, method, and serialization
public partial class LoginRequest : IApiRequest<LoginRequest, LoginResponse>
{
// Route extracted from endpoint's Configure() method
static string Route => "/api/admin/login";
// HTTP method (Post, Get, Put, Delete, Patch)
static HttpMethod Method => HttpMethod.Post;
// AOT-safe JSON serialization metadata
static JsonTypeInfo<LoginRequest> RequestTypeInfo => SharedJsonContext.Default.LoginRequest;
static JsonTypeInfo<LoginResponse> ResponseTypeInfo => SharedJsonContext.Default.LoginResponse;
}Clean, type-safe API calls with automatic serialization:
// Request types know their own route, method, and serialization
var (response, result) = await client.SendAsync(new LoginRequest
{
Email = "user@example.com",
Password = "pass"
});
// Response type is automatically inferred from IReturn<TResponse>
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Token: {result.Token}");
}Interactive API documentation available at localhost:5000/api in development mode.
Update - This issue has been resolved. Steps just noted.
Why this is safe:
- The custom
ResponseSerializerwrites the actual response data first - The exception occurs after the response is written, not during
- The buffer contains the complete, valid response
- Minimal performance overhead (exception filters have near-zero cost when no exception occurs)
See Web/Hostings/AotResponseBufferingMiddleware.cs for implementation details.
The ExternalAotTests require the published Native AOT app to be running on localhost:5000:
# Terminal 1: Start the published app
./publish/Web.exe
# Terminal 2: Run external AOT tests
dotnet test Tests\IntegrationTests\FastEndpointsThese tests validate the actual AOT-compiled binary against real HTTP requests.
cd Benchmark
./run-all-benchmarks.ps1The project is configured for Native AOT in Release mode:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<PublishAot>true</PublishAot>
<SelfContained>true</SelfContained>
<PublishTrimmed>true</PublishTrimmed>
<StripSymbols>true</StripSymbols>
</PropertyGroup>See LICENSE.md for details.
