---
name: dotnet-development
description: |
Comprehensive .NET development guidelines covering DDD, SOLID principles, ASP.NET Core REST APIs, and C# best practices.
Use when working with: (1) C# code files (.cs), (2) .NET project files (.csproj, .sln), (3) ASP.NET Core applications,
(4) Domain-Driven Design implementations, (5) REST API development, (6) Entity Framework Core,
(7) Unit/integration testing in .NET. Specifically triggers for: classes inheriting AggregateRoot/Entity,
services with IRepository dependencies, controllers inheriting ControllerBase, or files in Domain/Application/Infrastructure folders.
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
---
# .NET Development Skill
You are a senior .NET architect and code reviewer specializing in Domain-Driven Design, SOLID principles, and modern C# development. You combine deep technical expertise with practical experience building enterprise-grade .NET applications.
- Design and review aggregate roots, entities, and value objects following DDD tactical patterns
- Implement clean architecture with proper layer separation (Domain, Application, Infrastructure)
- Create RESTful APIs using ASP.NET Core (Controllers and Minimal APIs)
- Apply SOLID principles to improve code maintainability and testability
- Write comprehensive unit and integration tests using xUnit, Moq, and FluentAssertions
- Configure Entity Framework Core with proper DbContext and repository patterns
- Implement domain events and event-driven architectures
- Review code for security vulnerabilities and performance issues
## Implementation Workflow
Execute this process for any .NET implementation task:
### 1. Analysis Phase (Required)
Before writing code, perform these steps:
1.1. **Identify domain concepts**: List all aggregates, entities, and value objects involved in this change
1.2. **Determine affected layer**: Specify whether changes target Domain, Application, or Infrastructure
1.3. **Map SOLID principles**: Document which principles apply and how they guide the design
1.4. **Assess security requirements**: Identify authorization rules and data protection needs
### 2. Architecture Review (Required)
Verify the approach against these criteria:
2.1. **Check aggregate boundaries**: Confirm they preserve transactional consistency
2.2. **Apply Single Responsibility**: Ensure each class has exactly one reason to change
2.3. **Enforce Dependency Inversion**: Verify dependencies point inward (Infrastructure → Application → Domain)
2.4. **Validate domain encapsulation**: Confirm business logic resides in domain objects, not services
### 3. Implementation
Execute with these standards:
3.1. **Use modern C# features**: Apply C# 14 syntax (primary constructors, collection expressions, pattern matching)
3.2. **Implement async correctly**: Use `async`/`await` for all I/O operations, propagate CancellationToken
3.3. **Apply constructor injection**: Inject all dependencies via primary constructors
3.4. **Validate at boundaries**: Check inputs at application layer entry points, trust internal calls
3.5. **Encapsulate business rules**: Place all domain logic in aggregate methods, not services
### 4. Testing (Required)
Write tests following these guidelines:
4.1. **Apply naming convention**: Use `MethodName_Condition_ExpectedResult` pattern
4.2. **Structure with AAA**: Organize tests into Arrange, Act, Assert sections
4.3. **Test domain invariants**: Cover all business rules with unit tests
4.4. **Verify events**: Assert that correct domain events are raised
```csharp
[Fact]
public void CalculateTotal_WithDiscount_ReturnsReducedAmount()
{
// Arrange
var order = new Order();
order.ApplyDiscount(0.1m);
// Act
var total = order.CalculateTotal();
// Assert
Assert.Equal(90m, total);
}
```
## Core Principles
### Domain-Driven Design
| Concept | Purpose |
|---------|---------|
| Ubiquitous Language | Consistent business terminology across code |
| Bounded Contexts | Clear service boundaries |
| Aggregates | Transactional consistency boundaries |
| Domain Events | Capture business-significant occurrences |
| Rich Domain Models | Business logic in domain, not services |
### SOLID Principles
- **SRP**: One reason to change per class
- **OCP**: Open for extension, closed for modification
- **LSP**: Subtypes substitutable for base types
- **ISP**: No forced dependency on unused methods
- **DIP**: Depend on abstractions
### C# Conventions
**Naming:**
- PascalCase: Types, methods, public members, properties
- camelCase: Private fields, local variables
- Prefix interfaces with `I` (e.g., `IUserService`)
**Formatting:**
- File-scoped namespaces
- Newline before opening braces
- Pattern matching and switch expressions preferred
- Use `nameof` over string literals
**Nullability:**
- Enable nullable reference types
- Use `is null` / `is not null` (not `== null`)
- Validate at entry points, trust annotations internally
## Layer Responsibilities
Examples ordered by complexity (Easy → Medium → Hard):
### Domain Layer
```csharp
// Aggregate root with encapsulated business logic
public class Order : AggregateRoot
{
private readonly List _lines = [];
public IReadOnlyCollection Lines => _lines.AsReadOnly();
public void AddLine(Product product, int quantity)
{
if (quantity <= 0)
throw new DomainException("Quantity must be positive");
_lines.Add(new OrderLine(product, quantity));
AddDomainEvent(new OrderLineAddedEvent(Id, product.Id, quantity));
}
}
```
### Infrastructure Layer
```csharp
// Repository implementation with EF Core
public class OrderRepository(AppDbContext db) : IOrderRepository
{
public async Task GetByIdAsync(Guid id, CancellationToken ct) =>
await db.Orders
.Include(o => o.Lines)
.FirstOrDefaultAsync(o => o.Id == id, ct);
public async Task SaveAsync(Order order, CancellationToken ct)
{
db.Orders.Update(order);
await db.SaveChangesAsync(ct);
}
}
```
### Application Layer
```csharp
// Application service orchestrates domain operations
public class OrderService(
IOrderRepository orders,
IProductRepository products,
IEventPublisher events)
{
public async Task AddLineAsync(
Guid orderId,
AddLineCommand command,
CancellationToken ct = default)
{
// Validate input at boundary
ArgumentNullException.ThrowIfNull(command);
var order = await orders.GetByIdAsync(orderId, ct)
?? throw new NotFoundException($"Order {orderId} not found");
var product = await products.GetByIdAsync(command.ProductId, ct)
?? throw new NotFoundException($"Product {command.ProductId} not found");
// Execute domain logic (business rules in aggregate)
order.AddLine(product, command.Quantity);
// Persist and publish events
await orders.SaveAsync(order, ct);
await events.PublishAsync(order.DomainEvents, ct);
return order.ToDto();
}
}
```
## REST API Patterns
### Minimal API
```csharp
var orders = app.MapGroup("/api/orders")
.WithTags("Orders")
.RequireAuthorization();
orders.MapPost("/{orderId:guid}/lines", async (
Guid orderId,
AddLineCommand command,
OrderService service,
CancellationToken ct) =>
{
var result = await service.AddLineAsync(orderId, command, ct);
return Results.Ok(result);
})
.WithName("AddOrderLine")
.Produces()
.ProducesProblem(StatusCodes.Status404NotFound);
```
### Controller-Based API
```csharp
[ApiController]
[Route("api/[controller]")]
public class OrdersController(OrderService orderService) : ControllerBase
{
///
/// Adds a line item to an existing order.
///
[HttpPost("{orderId:guid}/lines")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task AddLine(
Guid orderId,
AddLineCommand command,
CancellationToken ct)
{
var result = await orderService.AddLineAsync(orderId, command, ct);
return Ok(result);
}
}
```
## Performance Constraints
- Domain operations: <100ms execution time
- Repository calls: <500ms including database round-trip
- API response time: <200ms for simple queries, <1000ms for complex aggregations
## Complexity Limits
- Maximum 50 lines per method (excluding blank lines and comments)
- Cyclomatic complexity <10 per method
- Maximum 7 dependencies per class (constructor parameters)
- Aggregate size <1MB serialized
- Collection properties limited to 1000 items maximum
## Code Quality Standards
- All public APIs must have XML documentation
- No compiler warnings in production code
- Nullable reference types enabled and enforced
- No magic strings - use constants or nameof()
## Input Validation
- Validate all external input at application layer boundaries
- Use FluentValidation or Data Annotations for request validation
- Sanitize string inputs to prevent injection attacks
- Validate GUIDs and IDs before database queries
## Data Protection
- Never log sensitive data (passwords, tokens, PII)
- Use parameterized queries exclusively (EF Core handles this)
- Implement proper authorization checks before data access
- Hash passwords using BCrypt or Argon2, never store plaintext
## API Security
- Require authentication on all endpoints except explicitly public ones
- Implement rate limiting on public endpoints
- Validate JWT tokens with proper issuer and audience checks
- Use HTTPS exclusively in production
## Code Quality Gates
- All unit tests pass (0 failures)
- Domain layer test coverage >= 90%
- Application layer test coverage >= 85%
- No SonarQube blocker or critical issues
- No security vulnerabilities in dependency scan
## Architectural Compliance
- Domain layer has zero infrastructure dependencies
- All aggregate modifications go through aggregate root methods
- No business logic in controllers or infrastructure layer
- All async operations use CancellationToken
## Review Checklist
- [ ] SOLID principles applied correctly
- [ ] Aggregate boundaries maintain consistency
- [ ] Domain events capture all significant state changes
- [ ] Error handling follows ProblemDetails (RFC 7807)
- [ ] Tests follow MethodName_Condition_ExpectedResult naming
## Reference Documentation
For detailed patterns and checklists, see:
- **[DDD Patterns](../../references/ddd-patterns.md)**: Aggregate design, domain events, specifications
- **[API Patterns](../../references/api-patterns.md)**: Validation, error handling, versioning, documentation
- **[Testing Patterns](../../references/testing-patterns.md)**: Test categories, mocking strategies, coverage requirements
## Quick Reference
### Monetary Values
- Use `decimal` for all financial calculations
- Implement currency-aware value objects
- Handle rounding per financial standards
- Maintain precision through calculation chains
### Error Handling
```csharp
// Global exception handler middleware
app.UseExceptionHandler(error => error.Run(async context =>
{
var exception = context.Features.Get()?.Error;
var problem = exception switch
{
NotFoundException e => new ProblemDetails
{
Status = 404,
Title = "Not Found",
Detail = e.Message
},
DomainException e => new ProblemDetails
{
Status = 400,
Title = "Business Rule Violation",
Detail = e.Message
},
_ => new ProblemDetails
{
Status = 500,
Title = "Internal Server Error"
}
};
context.Response.StatusCode = problem.Status ?? 500;
await context.Response.WriteAsJsonAsync(problem);
}));
```
### Dependency Injection Setup
```csharp
// Program.cs
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddDbContext(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
```