ASP.NET service template
dotnet new trellis-asp· NuGet packageTrellis.AspTemplate
A single, well-structured ASP.NET Core service built on the Trellis framework, using Domain-Driven Design and Railway-Oriented Programming. Reach for this when you're building one focused service rather than a fleet of them.
Solution structure
The template follows a strict, inward-pointing dependency flow:
MyService/
├── Domain/ # Aggregates, entities, value objects, domain events, specifications
├── Application/ # Commands, queries, handlers, repository interfaces
├── Acl/ # DbContext, EF Core configuration, repository implementations (the Anti-Corruption Layer)
├── Api/ # Controllers, DTOs, Program.cs, the composition root
└── *.slnx # Solution file
| Layer | May depend on | Never depends on |
|---|---|---|
| Domain | Trellis primitives only | EF Core, ASP.NET, Mediator |
| Application | Domain, Mediator | ASP.NET, EF providers |
| Acl | Application, EF Core | Api |
| Api | Application, Acl | Domain persistence details |
Why "Acl"? It's the Anti-Corruption Layer — it adapts external systems (SQL Server, queues, other services) to your domain model, instead of the vaguer "Infrastructure".
What's wired up
Out of the box the service has every cross-cutting capability: date-based API versioning, Service Level Indicators, idempotent writes, RFC 9457 ProblemDetails, an OpenAPI document with a Scalar UI, OpenTelemetry, actor-based authorization, the mediator pipeline, and health checks. EF Core is configured with Trellis conventions and interceptors.
API versioning by namespace
Controllers live in date-stamped folders and namespaces — one folder per version:
Api/src/2026-03-26/Controllers/TodosController.cs → namespace MyService.Api.v2026_03_26.Controllers
Api/src/2026-12-01/Controllers/TodosController.cs → namespace MyService.Api.v2026_12_01.Controllers
The version is derived from the namespace — no [ApiVersion] attributes to maintain. To add a version, copy
the latest folder, rename the namespace, and evolve it independently. Older versions stay frozen.
The reference implementation
A small Todo domain ships as a worked example of every pattern: scalar and composite value objects, a
RequiredEnum smart enum, an aggregate with a lazy state machine, always-valid commands with TryCreate,
resource-based authorization, repositories returning Maybe<T>, ETag concurrency, and version-mapped
controllers. Read it before replacing it — it's the fastest way to learn the conventions.
Build and test
dotnet build MyService.slnx -c Release # Release enforces code-style as errors
dotnet test --solution MyService.slnx -c Release --filter-not-trait "Category=Integration"
Tests use xUnit v3 on Microsoft.Testing.Platform — don't pass legacy VSTest flags such as --nologo
or --logger; the runner rejects them.