dotnet-core · diff

git:20260504.759031f to git:20260803.af106c2

36 added, 64 removed. Audit A to A.

---
name: dotnet-core
- description: "Apply these opinionated .NET 8 architecture recipes for backend services: clean architecture layering, CQRS with MediatR, minimal APIs, Entity Framework Core, JWT authentication, AOT compilation, cloud-native patterns."
+ description: "Apply these opinionated .NET 8 architecture conventions whenever structuring or reviewing a backend service: clean architecture layering and which direction dependencies point, when CQRS with MediatR is worth it, cross-cutting concerns as pipeline behaviours, minimal APIs grouped by feature, keeping DbContext in Infrastructure, health checks and structured logging, WebApplicationFactory integration tests, and when AOT pays off."
---
- # .NET Core Expert
-
- Senior .NET Core specialist with deep expertise in .NET 8, modern C#, minimal APIs, and cloud-native application development.
-
- ## Role Definition
-
- You are a senior .NET engineer with 10+ years of experience building enterprise applications. You specialize in .NET 8, C# 12, minimal APIs, Entity Framework Core, and cloud-native patterns. You build high-performance, scalable applications with clean architecture.
-
- ## When to Use This Skill
-
- - Building minimal APIs with .NET 8
- - Implementing clean architecture with CQRS/MediatR
- - Setting up Entity Framework Core with async patterns
- - Creating microservices with cloud-native patterns
- - Implementing JWT authentication and authorization
- - Optimizing performance with AOT compilation
-
- ## Core Workflow
-
- 1. **Analyze requirements** - Identify architecture pattern, data models, API design
- 2. **Design solution** - Create clean architecture layers with proper separation
- 3. **Implement** - Write high-performance code with modern C# features
- 4. **Secure** - Add authentication, authorization, and security best practices
- 5. **Test** - Write comprehensive tests with xUnit and integration testing
-
- ## Reference Guide
-
- Load detailed guidance based on context:
+ # .NET Core Architecture
- | Topic | Reference | Load When |
- | --- | --- | --- |
- | Minimal APIs | `references/minimal-apis.md` | Creating endpoints, routing, middleware |
- | Clean Architecture | `references/clean-architecture.md` | CQRS, MediatR, layers, DI patterns |
- | Entity Framework | `references/entity-framework.md` | DbContext, migrations, relationships |
- | Authentication | `references/authentication.md` | JWT, Identity, authorization policies |
- | Cloud-Native | `references/cloud-native.md` | Docker, health checks, configuration |
+ House architecture conventions for .NET 8 backend services. This covers how a service is _structured_; for language-level conventions see the `csharp` skill.
- ## Constraints
+ ## Layering
- ### MUST DO
+ Dependencies point inward only. Domain knows nothing about anything else, and Infrastructure is the one layer allowed to reference a database or an SDK — which is what lets the inner layers be tested without either.
- - Use .NET 8 and C# 12 features
- - Enable nullable reference types
- - Use async/await for all I/O operations
- - Implement proper dependency injection
- - Use record types for DTOs
- - Follow clean architecture principles
- - Write integration tests with WebApplicationFactory
- - Configure OpenAPI/Swagger documentation
+ ```text
+ Domain entities, value objects, domain events, interfaces → no dependencies
+ Application use cases, CQRS handlers, DTOs, validators → Domain
+ Infrastructure EF Core, external APIs, implementations of Domain interfaces → Domain + Application
+ Api endpoints, DI wiring, middleware → all of the above
+ ```
- ### MUST NOT DO
+ The test that keeps this honest: if `Domain` compiles with no package references beyond the BCL, the boundary is intact.
- - Use synchronous I/O operations
- - Expose entities directly in API responses
- - Store secrets in code or appsettings.json
- - Skip input validation
- - Use legacy .NET Framework patterns
- - Ignore compiler warnings
- - Mix concerns across architectural layers
- - Use deprecated EF Core patterns
+ Entities enforce their own invariants: private setters, a private parameterless constructor for EF Core's materialiser, and a static factory that validates. Public setters mean any layer can put the entity into an invalid state, and then "the domain guarantees X" is just a comment.
- ## Output Templates
+ ```csharp
+ public class Product
+ {
+ public string Name { get; private set; } = string.Empty;
+ public decimal Price { get; private set; }
- When implementing .NET features, provide:
+ private Product() { } // EF Core materialisation only
- 1. Project structure (solution/project files)
- 2. Domain models and DTOs
- 3. API endpoints or service implementations
- 4. Database context and migrations if applicable
- 5. Brief explanation of architectural decisions
+ public static Product Create(string name, decimal price) =>
+ price <= 0
+ ? throw new DomainException("Price must be greater than zero")
+ : new Product { Name = name, Price = price };
+ }
+ ```
- ## Knowledge Reference
+ ## Conventions
- .NET 8, C# 12, ASP.NET Core, minimal APIs, Entity Framework Core, MediatR, CQRS, clean architecture, dependency injection, JWT authentication, xUnit, Docker, Kubernetes, AOT compilation, OpenAPI/Swagger
+ - **CQRS with MediatR when reads and writes genuinely differ** — different models, different consistency, different scaling. On a CRUD service it is ceremony; adopt it because the domain asked for it, not by default.
+ - **Cross-cutting concerns go in pipeline behaviours**, not in handlers. Validation, logging, and transactions written once as a behaviour apply to every handler and can't be forgotten in a new one.
+ - **Minimal APIs grouped with `MapGroup`**, one file per feature area. A single `Program.cs` holding every endpoint stops being readable at about twenty routes.
+ - **Validation at the Application boundary** (FluentValidation in a behaviour), so the same rules apply no matter which entry point invoked the use case. Validation in the endpoint only guards HTTP.
+ - **DbContext stays in Infrastructure**, behind an interface the Application layer owns. Leaking `DbContext` into handlers ties your use cases to EF and makes them untestable without a provider.
+ - **Secrets never in `appsettings.json`** — user-secrets locally, environment or a vault in production. Anything committed is compromised, and rotating it means a redeploy.
+ - **Health checks (`/health/live`, `/health/ready`) and structured logging with correlation IDs** from the start. Retrofitting observability into a running incident is the wrong time to discover you have none. Keep the two probes genuinely different: readiness may check the database and downstream APIs, liveness must check only that the process itself is alive. A liveness probe that pings the database restarts every pod during a brief database blip, turning a recoverable dependency failure into a full outage.
+ - **Containers run as a non-root user.** Add a `USER` line — the default root container turns a process-level compromise into host-level reach, and it costs one line to prevent.
+ - **Integration tests over `WebApplicationFactory`** with a real database (Testcontainers). They exercise the DI graph, routing, serialisation, and EF mapping — the layers where mocked unit tests report success on a broken service.
+ - **AOT only where startup time or footprint justifies it.** It rules out runtime reflection, which quietly breaks some serialisers and DI patterns; verify the whole stack tolerates it before committing.