C# Cursor Rules: .NET Development Best Practices

Cursor rules for C# and .NET development covering async patterns, LINQ, dependency injection, Entity Framework, and clean architecture for enterprise applications.

September 5, 2024by PromptGenius Team
csharpcursor-rulesdotnetasyncentity-framework

Overview

C# and the .NET ecosystem power everything from massive enterprise systems to web APIs and Unity games. These cursor rules enforce modern C# 12+ features, robust async/await patterns, and dependency injection principles to help AI assistants generate clean, maintainable architecture. Whether you're building a cloud-native microservice or an Entity Framework backend, these rules ensure your codebase adheres to type-safe, scalable enterprise patterns.

Note:

Enforces nullable reference types, async/await patterns, LINQ best practices, and dependency injection principles for .NET development.

Rules Configuration

---
description: Enforces best practices for C# development, focusing on modern .NET patterns, async/await, LINQ, and dependency injection. Provides comprehensive guidelines for writing clean, type-safe enterprise code with proper context.
globs: **/*.cs
---
# C# Best Practices

You are an expert in C# and .NET development.
You understand modern C# development practices, architectural patterns, and the importance of providing complete context in code generation.

### Context-Aware Code Generation
- Provide complete class context including namespaces, using directives, and inheritance chain
- Include relevant project files (.csproj, appsettings.json) when generating application code
- Generate complete method signatures with proper return types, parameters, and XML docs
- Document the class responsibility and dependency requirements

### Code Style
- 4 spaces indentation
- PascalCase for classes, methods, properties, and public fields
- camelCase for local variables, parameters, and private fields
- 120 character line limit for readability
- Use file-scoped namespaces (namespace X; over namespace X {})

### Async/Await Patterns
- Use async/await for all I/O-bound operations (HTTP, database, file access)
- Avoid async void except for event handlers
- Use ValueTask for high-performance async paths that often complete synchronously
- ConfigureAwait(false) in library code to avoid deadlocks
- Use Task.WhenAll for concurrent independent operations

### LINQ & Functional Patterns
- Use LINQ method syntax (.Where, .Select, .OrderBy) over loop constructs
- Prefer records for immutable data DTOs and transfer objects
- Use pattern matching (switch expressions, property patterns) for type-safe branching
- Use nullable reference types to express nullability intent
- Use immutable collections (ImmutableArray, ImmutableDictionary) for shared state

### Dependency Injection
- Use constructor injection for all service dependencies
- Register services with appropriate lifetime (Singleton, Scoped, Transient)
- Use IHttpClientFactory for typed HTTP clients with connection pooling
- Register DbContext with AddDbContext and scoped lifetime
- Avoid service locator pattern; inject only what the class needs

### Entity Framework
- Use DbContext with scoped lifetime per HTTP request
- Use async LINQ methods (ToListAsync, FirstOrDefaultAsync) for database queries
- Configure indexes and relationships via Fluent API in OnModelCreating
- Use migrations for schema changes; never modify production databases directly
- Use AsNoTracking for read-only queries to improve performance

### Testing & Quality
- Write unit tests with xUnit or NUnit and FluentAssertions
- Mock dependencies with Moq or NSubstitute in unit tests
- Use Testcontainers for integration tests with real databases
- Run dotnet format for consistent code style across the team
- Enable .NET analyzers with EnforceCodeStyleInBuild for CI enforcement

### Build & Deployment
- Use C# 12+ features (primary constructors, collection expressions) for concise code
- Generate nullable-safe code with nullable enabled in project config
- Include XML documentation generation in Release builds
- Use middleware (ExceptionHandler, Serilog) in Program.cs for cross-cutting concerns

Installation

Create csharp.mdc in your project's .cursor/rules/ directory and paste the configuration above. Cursor and Windsurf both read .cursor/rules/ — Copilot users place it in .github/copilot-instructions.md instead.

Examples

// Services/UserService.cs — Constructor DI with async/await
public interface IUserService
{
    Task<User?> FindByEmailAsync(string email);
}

public class UserService : IUserService
{
    private readonly AppDbContext _db;
    private readonly ILogger<UserService> _logger;

    public UserService(AppDbContext db, ILogger<UserService> logger)
    {
        _db = db;
        _logger = logger;
    }

    public async Task<User?> FindByEmailAsync(string email)
    {
        return await _db.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(u => u.Email == email);
    }
}
// Program.cs — Modern .NET host configuration
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(opts =>
    opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddControllers();

var app = builder.Build();
app.UseMiddleware<ExceptionHandler>();
app.MapControllers();
app.Run();