dotnet-architecture-patterns
Modern architecture patterns for .NET applications. Covers practical approaches to organizing minimal APIs at scale,
vertical slice architecture, request pipeline composition, validation strategies, caching, error handling, and
idempotency/outbox patterns.
Scope
- Vertical slice architecture and feature-folder organization
- Request pipeline composition and MediatR patterns
- Caching strategies (memory, distributed, output caching, HybridCache)
- Error handling and problem details (RFC 9457)
- Idempotency and outbox patterns
- Result pattern for business logic error flow
Out of scope
- DI container mechanics and async/await patterns -- see [skill:dotnet-csharp-dependency-injection] and
[skill:dotnet-csharp-async-patterns]
- Project scaffolding and file layout -- see [skill:dotnet-scaffold-project]
- Testing strategies -- see [skill:dotnet-testing-strategy] and [skill:dotnet-integration-testing]
- SOLID principles and design pattern foundations -- see [skill:dotnet-solid-principles]
Cross-references: [skill:dotnet-csharp-dependency-injection] for service registration and lifetimes,
[skill:dotnet-csharp-async-patterns] for async pipeline patterns, [skill:dotnet-csharp-configuration] for Options
pattern in configuration, [skill:dotnet-solid-principles] for SOLID/DRY design principles governing class and interface
design.
For detailed code examples (vertical slices, minimal API organization, pipeline composition, error handling, caching,
idempotency, outbox), see examples.md in this skill directory.
Agent Gotchas
- Idempotency must handle three states -- An idempotency implementation must distinguish no-record (claim it),
in-progress (reject duplicate), and completed (replay cached response). Check-then-act without guarding the
in-progress state allows concurrent duplicate execution.
- Always finalize idempotency records unconditionally -- Do NOT gate completion on specific
IResult subtypes
(e.g., IValueHttpResult). Non-value results like Results.NoContent() or Results.Accepted() would be left
permanently stuck in the in-progress state.
- Cache invalidation must be explicit -- When using output caching or distributed caching, ALWAYS invalidate (evict
by tag or key) after write operations. Forgetting invalidation causes stale reads that are hard to debug.
- HybridCache stampede protection only works with
GetOrCreateAsync -- Do NOT use separate get-then-set patterns
with HybridCache; use the factory overload so the library serializes concurrent requests for the same key.
- Outbox messages must be written in the same transaction as domain data -- If you write the outbox message outside
the domain transaction, a crash between the two writes loses the event. ALWAYS use
BeginTransactionAsync to wrap
both writes atomically.
- Endpoint filter order matters -- Filters added first run outermost. A validation filter must run before an
idempotency filter, otherwise invalid requests get cached as idempotent responses.
- Do NOT share
DbContext across concurrent requests -- DbContext is not thread-safe. Each request must resolve
its own scoped instance from DI. Using a singleton or static DbContext causes data corruption under concurrency.
Knowledge Sources
Architecture patterns in this skill are grounded in publicly available content from:
- Jimmy Bogard's Vertical Slice Architecture -- Organizing code by feature instead of by technical layer. Bogard
advocates that each vertical slice owns its own request, handler, validation, and data access, reducing cross-feature
coupling. He originated the popular MediatR library for request/handler dispatch in .NET, though MediatR is now
commercial for commercial use. When applying vertical slice guidance, prefer the built-in IEndpointFilter and handler
pattern shown above rather than introducing a third-party mediator dependency for simple scenarios. Source:
https://www.jimmybogard.com/vertical-slice-architecture/
- Jimmy Bogard's Domain-Driven Design Patterns -- Rich domain model guidance including entity design, value objects,
domain events, and aggregate boundaries. Key insight: domain events should be dispatched after the aggregate state
change is persisted (not before), to avoid inconsistency if persistence fails. Source: https://www.jimmybogard.com/
- Nick Chapsas' Modern .NET Patterns -- Practical patterns for modern .NET including result types for error
handling, structured validation pipelines, and modern C# feature adoption in production codebases. Source:
https://www.youtube.com/@nickchapsas
Note: This skill applies publicly documented guidance. It does not represent or speak for the named sources.
MediatR is a commercial product for commercial use; the patterns here are demonstrated with built-in .NET mechanisms.
Code Navigation (Serena MCP)
Primary approach: Use Serena symbol operations for efficient code navigation:
- Find definitions:
serena_find_symbol instead of text search
- Understand structure:
serena_get_symbols_overview for file organization
- Track references:
serena_find_referencing_symbols for impact analysis
- Precise edits:
serena_replace_symbol_body for clean modifications
When to use Serena vs traditional tools:
- ✅ Use Serena: Navigation, refactoring, dependency analysis, precise edits
- ✅ Use Read/Grep: Reading full files, pattern matching, simple text operations
- ✅ Fallback: If Serena unavailable, traditional tools work fine
Example workflow:
# Instead of:
Read: src/Services/OrderService.cs
Grep: "public void ProcessOrder"
# Use:
serena_find_symbol: "OrderService/ProcessOrder"
serena_get_symbols_overview: "src/Services/OrderService.cs"
References
1---2name: dotnet-architecture-patterns3description: Designs ASP.NET Core architecture -- vertical slices, pipelines, caching, errors.4license: MIT5---67# dotnet-architecture-patterns89Modern architecture patterns for .NET applications. Covers practical approaches to organizing minimal APIs at scale,10vertical slice architecture, request pipeline composition, validation strategies, caching, error handling, and11idempotency/outbox patterns.1213## Scope1415- Vertical slice architecture and feature-folder organization16- Request pipeline composition and MediatR patterns17- Caching strategies (memory, distributed, output caching, HybridCache)18- Error handling and problem details (RFC 9457)19- Idempotency and outbox patterns20- Result pattern for business logic error flow2122## Out of scope2324- DI container mechanics and async/await patterns -- see [skill:dotnet-csharp-dependency-injection] and25 [skill:dotnet-csharp-async-patterns]26- Project scaffolding and file layout -- see [skill:dotnet-scaffold-project]27- Testing strategies -- see [skill:dotnet-testing-strategy] and [skill:dotnet-integration-testing]28- SOLID principles and design pattern foundations -- see [skill:dotnet-solid-principles]2930Cross-references: [skill:dotnet-csharp-dependency-injection] for service registration and lifetimes,31[skill:dotnet-csharp-async-patterns] for async pipeline patterns, [skill:dotnet-csharp-configuration] for Options32pattern in configuration, [skill:dotnet-solid-principles] for SOLID/DRY design principles governing class and interface33design.3435---3637For detailed code examples (vertical slices, minimal API organization, pipeline composition, error handling, caching,38idempotency, outbox), see `examples.md` in this skill directory.3940## Agent Gotchas41421. **Idempotency must handle three states** -- An idempotency implementation must distinguish no-record (claim it),43 in-progress (reject duplicate), and completed (replay cached response). Check-then-act without guarding the44 in-progress state allows concurrent duplicate execution.452. **Always finalize idempotency records unconditionally** -- Do NOT gate completion on specific `IResult` subtypes46 (e.g., `IValueHttpResult`). Non-value results like `Results.NoContent()` or `Results.Accepted()` would be left47 permanently stuck in the in-progress state.483. **Cache invalidation must be explicit** -- When using output caching or distributed caching, ALWAYS invalidate (evict49 by tag or key) after write operations. Forgetting invalidation causes stale reads that are hard to debug.504. **HybridCache stampede protection only works with `GetOrCreateAsync`** -- Do NOT use separate get-then-set patterns51 with `HybridCache`; use the factory overload so the library serializes concurrent requests for the same key.525. **Outbox messages must be written in the same transaction as domain data** -- If you write the outbox message outside53 the domain transaction, a crash between the two writes loses the event. ALWAYS use `BeginTransactionAsync` to wrap54 both writes atomically.556. **Endpoint filter order matters** -- Filters added first run outermost. A validation filter must run before an56 idempotency filter, otherwise invalid requests get cached as idempotent responses.577. **Do NOT share `DbContext` across concurrent requests** -- `DbContext` is not thread-safe. Each request must resolve58 its own scoped instance from DI. Using a singleton or static `DbContext` causes data corruption under concurrency.5960---6162## Knowledge Sources6364Architecture patterns in this skill are grounded in publicly available content from:6566- **Jimmy Bogard's Vertical Slice Architecture** -- Organizing code by feature instead of by technical layer. Bogard67 advocates that each vertical slice owns its own request, handler, validation, and data access, reducing cross-feature68 coupling. He originated the popular MediatR library for request/handler dispatch in .NET, though MediatR is now69 commercial for commercial use. When applying vertical slice guidance, prefer the built-in IEndpointFilter and handler70 pattern shown above rather than introducing a third-party mediator dependency for simple scenarios. Source:71 https://www.jimmybogard.com/vertical-slice-architecture/72- **Jimmy Bogard's Domain-Driven Design Patterns** -- Rich domain model guidance including entity design, value objects,73 domain events, and aggregate boundaries. Key insight: domain events should be dispatched after the aggregate state74 change is persisted (not before), to avoid inconsistency if persistence fails. Source: https://www.jimmybogard.com/75- **Nick Chapsas' Modern .NET Patterns** -- Practical patterns for modern .NET including result types for error76 handling, structured validation pipelines, and modern C# feature adoption in production codebases. Source:77 https://www.youtube.com/@nickchapsas7879> **Note:** This skill applies publicly documented guidance. It does not represent or speak for the named sources.80> MediatR is a commercial product for commercial use; the patterns here are demonstrated with built-in .NET mechanisms.8182## Code Navigation (Serena MCP)8384**Primary approach:** Use Serena symbol operations for efficient code navigation:85861. **Find definitions**: `serena_find_symbol` instead of text search872. **Understand structure**: `serena_get_symbols_overview` for file organization883. **Track references**: `serena_find_referencing_symbols` for impact analysis894. **Precise edits**: `serena_replace_symbol_body` for clean modifications9091**When to use Serena vs traditional tools:**9293- ✅ **Use Serena**: Navigation, refactoring, dependency analysis, precise edits94- ✅ **Use Read/Grep**: Reading full files, pattern matching, simple text operations95- ✅ **Fallback**: If Serena unavailable, traditional tools work fine9697**Example workflow:**9899```text100# Instead of:101Read: src/Services/OrderService.cs102Grep: "public void ProcessOrder"103104# Use:105serena_find_symbol: "OrderService/ProcessOrder"106serena_get_symbols_overview: "src/Services/OrderService.cs"107```108109## References110111- [ASP.NET Core Best Practices](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/best-practices?view=aspnetcore-10.0)112- [Minimal APIs overview](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/overview)113- [Output caching middleware](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/output)114- [HybridCache library](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/hybrid)115- [Problem Details (RFC 9457)](https://www.rfc-editor.org/rfc/rfc9457)116- [Endpoint filters in minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/min-api-filters)117- [Vertical Slice Architecture (Jimmy Bogard)](https://www.jimmybogard.com/vertical-slice-architecture/)