CLAUDE.md — C# / .NET Project
Project Basics
This is a C# project using .NET 8+. Use nullable reference types (<Nullable>enable</Nullable>). Prefer records for DTOs, file-scoped namespaces, and primary constructors where appropriate. All code must compile with zero warnings.
Project Structure
src/— source projectstests/— test projects (mirror source structure)- One project per bounded context or major feature area
- Shared code in a
.Commonor.Sharedproject - Keep
Program.csminimal — register services, configure pipeline, run
Naming Conventions
PascalCasefor types, methods, properties, and public memberscamelCasefor local variables and parameters_camelCasefor private fieldsIPascalCasefor interfaces (C# convention, unlike Java)- Async methods end with
Async:GetUserAsync()
Dependency Injection
- Constructor injection via built-in DI container
- Register services in
Program.csor extension methods:services.AddScoped<IUserService, UserService>() - Use
IOptions<T>for configuration binding - Avoid service locator pattern — don’t resolve services from
IServiceProviderdirectly
Error Handling
- Use middleware for global exception handling, not try/catch in every controller
- Define custom exceptions for domain errors with meaningful messages
- Return
ProblemDetails(RFC 7807) for API error responses - Use
Result<T>pattern for operations that can fail predictably - Never expose stack traces in production responses
Entity Framework Core
- Code-first migrations:
dotnet ef migrations add <Name> - DbContext registration:
services.AddDbContext<AppDbContext>() - Use
AsNoTracking()for read-only queries - Avoid lazy loading — use explicit
Include()for related data - Index frequently queried columns in migration files
Testing
- xUnit for test framework
- NSubstitute or Moq for mocking
WebApplicationFactory<Program>for integration tests- Use
[Theory]with[InlineData]for parameterized tests - Test naming:
MethodName_Scenario_ExpectedResult - Testcontainers for database integration tests
API Design
- Minimal APIs or Controllers — be consistent within the project
- Use
[FromBody],[FromQuery],[FromRoute]explicitly - Return
IActionResultorResultswith proper status codes - Use FluentValidation or Data Annotations for request validation
- Swagger/OpenAPI: keep
[ProducesResponseType]attributes up to date
Async Patterns
- Use
async/awaitfor all I/O operations - Never use
.Resultor.Wait()— it causes deadlocks - Use
CancellationTokenin controller actions and propagate through the call chain ValueTaskonly when the common path completes synchronously
Build & Deploy
dotnet build— must pass with zero warningsdotnet publish -c Releasefor deployment artifacts- Docker: multi-stage build with
mcr.microsoft.com/dotnet/sdk→mcr.microsoft.com/dotnet/aspnet - Use
appsettings.{Environment}.jsonfor environment-specific config - Never commit
appsettings.Development.jsonwith real secrets — use User Secrets or environment variables
Verification
dotnet build --warnaserror— compiles with zero warningsdotnet test— all tests passdotnet format --verify-no-changes— properly formatted- Application starts without errors
Git & GitHub
- Do not push code or create PRs without explicit permission
- Do not perform destructive or irreversible operations without asking first
- Never commit
appsettings.*.jsonwith connection strings or secrets