C# Best Practices

Learn industry-standard practices and patterns to write clean, maintainable, and efficient C# code.

All Best Practices

Coding Standards

9 practices
Essential
Use Meaningful Names

Choose descriptive names for variables, methods, and classes that clearly express their purpose.

Good Example
// Good
public class CustomerOrderProcessor
{
    private readonly IPaymentService _paymentService;
    
    public async Task<OrderResult> ProcessCustomerOrderAsync(Order order)
    {
        // Implementation
    }
}
Bad Example
// Bad
public class COP
{
    private readonly IPS ps;
    
    public async Task<OR> ProcessAsync(O o)
    {
        // Implementation
    }
}
Essential
Follow C# Naming Conventions

Use PascalCase for public members, camelCase for private fields, and consistent naming patterns.

Good Example
// Good
public class ProductService
{
    private readonly ILogger _logger;
    private const int MaxRetryAttempts = 3;
    
    public async Task<Product> GetProductByIdAsync(int productId)
    {
        // Implementation
    }
}
Bad Example
// Bad
public class productservice
{
    private readonly ILogger Logger;
    private const int max_retry_attempts = 3;
    
    public async Task<Product> getproductbyid(int ProductID)
    {
        // Implementation
    }
}
Essential
Use Consistent Indentation

Maintain consistent indentation throughout your code to improve readability and maintainability.

Good Example
// Good
public class Example
{
    public void Method()
    {
        if (condition)
        {
            // Do something
        }
    }
}
Bad Example
// Bad
public class Example
{
public void Method()
{
if (condition)
{
// Do something
}
}
}
Important
Limit Line Length

Keep line length to a reasonable limit (e.g., 80-100 characters) to enhance code readability.

Good Example
// Good
public class Example
{
    public void Method()
    {
        var longString = "This is a long string that is split " +
                         "across multiple lines for better readability.";
    }
}
Bad Example
// Bad
public class Example
{
    public void Method()
    {
        var longString = "This is a long string that is not split across multiple lines, making it hard to read.";
    }
}
Important
Avoid Magic Numbers

Use named constants instead of magic numbers to make your code more understandable and maintainable.

Good Example
// Good
public class Circle
{
    private const double Pi = 3.14159;
    public double CalculateCircumference(double radius)
    {
        return 2 * Pi * radius;
    }
}
Bad Example
// Bad
public class Circle
{
    public double CalculateCircumference(double radius)
    {
        return 2 * 3.14159 * radius;
    }
}
Essential
Use Comments Wisely

Write comments to explain why code exists, not what it does. Keep comments up-to-date.

Good Example
// Good
public class DataProcessor
{
    // This method processes data from the input stream and applies necessary transformations.
    public void ProcessData(Stream inputStream)
    {
        // Implementation
    }
}
Bad Example
// Bad
public class DataProcessor
{
    // Process data
    public void ProcessData(Stream inputStream)
    {
        // Implementation
    }
}
Important
Encapsulate Conditionals

Encapsulate complex conditionals in methods to improve readability and maintainability.

Good Example
// Good
public class Order
{
    public bool IsEligibleForDiscount(Customer customer)
    {
        return customer.IsLoyal && customer.TotalOrders > 10;
    }
}
Bad Example
// Bad
public class Order
{
    public bool IsEligibleForDiscount(Customer customer)
    {
        return customer.IsLoyal && customer.TotalOrders > 10 && customer.HasCoupon;
    }
}
Critical
Use Exception Handling

Implement proper exception handling to manage errors gracefully and maintain application stability.

Good Example
// Good
public class FileProcessor
{
    public void ProcessFile(string filePath)
    {
        try
        {
            // File processing logic
        }
        catch (IOException ex)
        {
            // Handle I/O exceptions
        }
    }
}
Bad Example
// Bad
public class FileProcessor
{
    public void ProcessFile(string filePath)
    {
        // File processing logic without exception handling
    }
}
Critical
Implement Proper Error Logging

Use a consistent logging framework to log errors with sufficient context to aid in debugging.

Good Example
// Good
public class UserService
{
    private readonly ILogger<UserService> _logger;

    public UserService(ILogger<UserService> logger)
    {
        _logger = logger;
    }

    public void CreateUser(User user)
    {
        try
        {
            // User creation logic
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error creating user {UserId}", user.Id);
        }
    }
}
Bad Example
// Bad
public class UserService
{
    public void CreateUser(User user)
    {
        try
        {
            // User creation logic
        }
        catch (Exception)
        {
            Console.WriteLine("An error occurred.");
        }
    }
}

Performance

8 practices
Important
Use StringBuilder for String Concatenation

When concatenating multiple strings, especially in loops, use StringBuilder for better performance.

Good Example
// Good
var sb = new StringBuilder();
foreach (var item in items)
{
    sb.AppendLine($"Item: {item.Name}");
}
string result = sb.ToString();
Bad Example
// Bad
string result = "";
foreach (var item in items)
{
    result += $"Item: {item.Name}\n";
}
Critical
Prefer Async/Await for I/O Operations

Use asynchronous programming for I/O bound operations to improve scalability.

Good Example
// Good
public async Task<string> GetDataAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://api.example.com/data");
}
Bad Example
// Bad
public string GetData()
{
    using var client = new HttpClient();
    return client.GetStringAsync("https://api.example.com/data").Result;
}
Important
Optimize LINQ Queries

Use efficient LINQ queries to minimize performance overhead and improve execution speed.

Good Example
// Good
var result = data.Where(x => x.IsActive).Select(x => x.Name).ToList();
// Use method syntax for better performance
var result = (from x in data
              where x.IsActive
              select x.Name).ToList();
Bad Example
// Bad
var result = data.Select(x => x.Name).Where(x => x.IsActive).ToList();
Critical
Leverage Parallel Processing

Utilize parallel processing to perform tasks concurrently and improve application throughput.

Good Example
// Good
Parallel.ForEach(data, item =>
{
    ProcessItem(item);
});
Bad Example
// Bad
foreach (var item in data)
{
    ProcessItem(item);  // Sequential processing
}
Important
Optimize Data Structures

Choose the right data structures for your needs to improve performance and memory usage.

Good Example
// Good
List<int> numbers = new List<int>();
for (int i = 0; i < 1000; i++)
{
    numbers.Add(i);
}
Bad Example
// Bad
ArrayList numbers = new ArrayList();
for (int i = 0; i < 1000; i++)
{
    numbers.Add(i);
}
Important
Minimize Boxing and Unboxing

Avoid unnecessary boxing and unboxing to reduce overhead and improve performance.

Good Example
// Good
int number = 123;
object obj = number;  // Boxing
int unboxedNumber = (int)obj;  // Unboxing
// Better
int number = 123;
int sameNumber = number;
Bad Example
// Bad
int number = 123;
object obj = number;  // Boxing
int unboxedNumber = (int)obj;  // Unboxing
Critical
Use Caching Strategically

Implement caching to store frequently accessed data and reduce computation time.

Good Example
// Good
public class DataService
{
    private readonly IMemoryCache _cache;

    public DataService(IMemoryCache cache)
    {
        _cache = cache;
    }

    public string GetData(string key)
    {
        if (!_cache.TryGetValue(key, out string data))
        {
            data = FetchDataFromSource(key);
            _cache.Set(key, data);
        }
        return data;
    }
}
Bad Example
// Bad
public class DataService
{
    public string GetData(string key)
    {
        return FetchDataFromSource(key);  // No caching
    }
}
Important
Avoid Unnecessary Object Creation

Reuse objects instead of creating new ones to reduce memory usage and improve performance.

Good Example
// Good
public class ConnectionManager
{
    private readonly SqlConnection _connection = new SqlConnection();

    public SqlConnection GetConnection()
    {
        return _connection;
    }
}
Bad Example
// Bad
public class ConnectionManager
{
    public SqlConnection GetConnection()
    {
        return new SqlConnection();  // Creates a new connection every time
    }
}

Security

15 practices
Critical
Validate Input Parameters

Always validate input parameters to prevent security vulnerabilities and unexpected behavior.

Good Example
// Good
public void ProcessUser(string email, int age)
{
    if (string.IsNullOrWhiteSpace(email))
        throw new ArgumentException("Email cannot be null or empty", nameof(email));
    
    if (age < 0 || age > 150)
        throw new ArgumentOutOfRangeException(nameof(age), "Age must be between 0 and 150");
    
    // Process user
}
Bad Example
// Bad
public void ProcessUser(string email, int age)
{
    // No validation - potential security risk
    var user = new User { Email = email, Age = age };
    // Process user
}
Critical
Use HTTPS for Secure Communication

Ensure all data transmitted between the client and server is encrypted using HTTPS.

Good Example
// Good
public void Configure(IApplicationBuilder app)
{
    app.UseHttpsRedirection();
    // Other middleware
}
Bad Example
// Bad
public void Configure(IApplicationBuilder app)
{
    // No HTTPS redirection
    // Other middleware
}
Critical
Implement Authentication and Authorization

Use authentication and authorization to protect resources and ensure only authorized users can access them.

Good Example
// Good
services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.Authority = "https://your-auth-server.com";
    options.Audience = "your-audience";
});

services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
Bad Example
// Bad
// No authentication or authorization setup
services.AddAuthorization();
Critical
Sanitize User Input

Always sanitize user input to prevent injection attacks such as SQL injection and cross-site scripting (XSS).

Good Example
// Good
public void ExecuteQuery(string userInput)
{
    var sanitizedInput = Sanitize(userInput);
    // Use sanitizedInput in database query
}
Bad Example
// Bad
public void ExecuteQuery(string userInput)
{
    // Directly using userInput in database query
}
Critical
Use Secure Password Storage

Store passwords securely using strong hashing algorithms like bcrypt.

Good Example
// Good
public void StorePassword(string password)
{
    var hashedPassword = BCrypt.Net.BCrypt.HashPassword(password);
    // Store hashedPassword in database
}
Bad Example
// Bad
public void StorePassword(string password)
{
    // Storing plain text password in database
}
Important
Regularly Update Dependencies

Keep all libraries and dependencies up to date to protect against known vulnerabilities.

Good Example
// Good
// Regularly check for updates and apply them
// Use tools like Dependabot or npm audit to automate this process
Bad Example
// Bad
// Ignoring dependency updates
// Using outdated libraries with known vulnerabilities
Important
Implement Rate Limiting

Use rate limiting to protect your application from abuse and denial-of-service attacks.

Good Example
// Good
public void Configure(IApplicationBuilder app)
{
    app.UseRateLimiting();
    // Other middleware
}
Bad Example
// Bad
public void Configure(IApplicationBuilder app)
{
    // No rate limiting
    // Other middleware
}
Critical
Use Content Security Policy (CSP)

Implement CSP to prevent cross-site scripting (XSS) and other code injection attacks.

Good Example
// Good
public void Configure(IApplicationBuilder app)
{
    app.UseCsp(options => options
        .DefaultSources(s => s.Self())
        .ScriptSources(s => s.Self().CustomSources("https://trustedscripts.example.com"))
        .StyleSources(s => s.Self().UnsafeInline())
    );
    // Other middleware
}
Bad Example
// Bad
public void Configure(IApplicationBuilder app)
{
    // No CSP implementation
    // Other middleware
}
Important
Secure Cookies

Ensure cookies are secure by setting the Secure and HttpOnly flags.

Good Example
// Good
var cookieOptions = new CookieOptions
{
    Secure = true, // Ensures the cookie is sent over HTTPS only
    HttpOnly = true // Prevents JavaScript access to the cookie
};
Response.Cookies.Append("SessionId", sessionId, cookieOptions);
Bad Example
// Bad
var cookieOptions = new CookieOptions
{
    // No Secure or HttpOnly flags
};
Response.Cookies.Append("SessionId", sessionId, cookieOptions);
Important
Implement Security Headers

Add security headers like X-Content-Type-Options, X-Frame-Options, and X-XSS-Protection to enhance security.

Good Example
// Good
public void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
        context.Response.Headers.Add("X-Frame-Options", "DENY");
        context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
        await next();
    });
    // Other middleware
}
Bad Example
// Bad
public void Configure(IApplicationBuilder app)
{
    // No security headers
    // Other middleware
}
Critical
Use Strong Encryption Algorithms

Ensure that strong encryption algorithms are used for data protection.

Good Example
// Good
public void EncryptData(string data)
{
    using (Aes aes = Aes.Create())
    {
        aes.Key = GenerateStrongKey();
        // Encryption logic
    }
}
Bad Example
// Bad
public void EncryptData(string data)
{
    using (Aes aes = Aes.Create())
    {
        aes.Key = GenerateWeakKey();
        // Encryption logic
    }
}
Critical
Implement Access Controls

Ensure that access controls are in place to restrict access to sensitive data and operations.

Good Example
// Good
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
    });
}
Bad Example
// Bad
// No access control policies defined
services.AddAuthorization();
Important
Monitor and Audit Logs

Regularly monitor and audit logs to detect and respond to security incidents.

Good Example
// Good
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    app.Use(async (context, next) =>
    {
        logger.LogInformation("Request: {Method} {Path}", context.Request.Method, context.Request.Path);
        await next();
    });
    // Other middleware
}
Bad Example
// Bad
public void Configure(IApplicationBuilder app)
{
    // No logging or monitoring
    // Other middleware
}
Critical
Conduct Regular Security Testing

Perform regular security testing, including vulnerability scans and penetration testing, to identify and address security weaknesses.

Good Example
// Good
// Schedule regular security assessments
// Use tools like OWASP ZAP or Nessus for automated scans
Bad Example
// Bad
// No regular security testing
// Ignoring potential vulnerabilities
Important
Educate and Train Employees

Provide regular security training to employees to raise awareness and reduce the risk of human error.

Good Example
// Good
// Conduct regular security workshops and training sessions
// Keep employees informed about the latest security threats
Bad Example
// Bad
// No security training for employees
// Lack of awareness about security best practices

Architecture

13 practices
Important
Use Dependency Injection

Implement dependency injection to create loosely coupled, testable code.

Good Example
// Good
public class OrderService
{
    private readonly IPaymentProcessor _paymentProcessor;
    private readonly IEmailService _emailService;
    
    public OrderService(IPaymentProcessor paymentProcessor, IEmailService emailService)
    {
        _paymentProcessor = paymentProcessor;
        _emailService = emailService;
    }
}
Bad Example
// Bad
public class OrderService
{
    private readonly PaymentProcessor _paymentProcessor = new PaymentProcessor();
    private readonly EmailService _emailService = new EmailService();
}
Critical
Implement Microservices Architecture

Design your application as a collection of loosely coupled services to improve scalability and maintainability.

Good Example
// Good
public class OrderService
{
    public void ProcessOrder(Order order)
    {
        // Logic to process order
    }
}

// Microservice setup
public class OrderMicroservice
{
    private readonly OrderService _orderService;

    public OrderMicroservice(OrderService orderService)
    {
        _orderService = orderService;
    }

    public void Start()
    {
        // Start microservice
    }
}
Bad Example
// Bad
public class MonolithicOrderProcessor
{
    public void ProcessOrder(Order order)
    {
        // Logic to process order
        // All logic in one place
    }
}
Important
Use Event-Driven Architecture

Implement event-driven architecture to decouple components and improve responsiveness.

Good Example
// Good
public class EventPublisher
{
    public void PublishEvent(Event event)
    {
        // Logic to publish event
    }
}

public class EventSubscriber
{
    public void Subscribe()
    {
        // Logic to subscribe to events
    }
}
Bad Example
// Bad
public class TightlyCoupledComponent
{
    public void Execute()
    {
        // Direct calls to other components
    }
}
Critical
Implement Domain-Driven Design (DDD)

Use DDD to align your software model with business needs and improve communication between technical and non-technical stakeholders.

Good Example
// Good
public class CustomerAggregate
{
    public void AddOrder(Order order)
    {
        // Logic to add order to customer
    }
}
Bad Example
// Bad
public class Customer
{
    public void AddOrder(Order order)
    {
        // Logic scattered across multiple classes
    }
}
Important
Adopt a Layered Architecture

Structure your application into layers (e.g., presentation, business, data) to separate concerns and improve maintainability.

Good Example
// Good
public class PresentationLayer
{
    public void DisplayData()
    {
        // Logic to display data
    }
}

public class BusinessLayer
{
    public void ProcessData()
    {
        // Logic to process data
    }
}
Bad Example
// Bad
public class MonolithicApplication
{
    public void Execute()
    {
        // All logic in one place
    }
}
Important
Implement CQRS (Command Query Responsibility Segregation)

Separate the read and write operations of your application to optimize performance and scalability.

Good Example
// Good
public class CommandHandler
{
    public void HandleCommand(Command command)
    {
        // Logic to handle command
    }
}

public class QueryHandler
{
    public TResult HandleQuery<TResult>(Query query)
    {
        // Logic to handle query
        return default(TResult);
    }
}
Bad Example
// Bad
public class UnifiedHandler
{
    public void HandleRequest(Request request)
    {
        // Mixed logic for handling commands and queries
    }
}
Critical
Use API Gateway Pattern

Implement an API Gateway to manage and route requests to various microservices, providing a single entry point.

Good Example
// Good
public class ApiGateway
{
    public void RouteRequest(Request request)
    {
        // Logic to route request to appropriate microservice
    }
}
Bad Example
// Bad
public class DirectClientAccess
{
    public void AccessService(Service service)
    {
        // Direct access to microservices without a gateway
    }
}
Important
Adopt Semantic Versioning

Use semantic versioning (MAJOR.MINOR.PATCH) to communicate changes in your API or software effectively.

Good Example
// Good
// Version 1.0.0 - Initial release
// Version 1.1.0 - Added new features
// Version 2.0.0 - Breaking changes introduced
Bad Example
// Bad
// Version 1 - Initial release
// Version 2 - Added new features and breaking changes
Critical
Version Your APIs

Ensure your APIs are versioned to manage changes and maintain backward compatibility.

Good Example
// Good
// API v1
[Route("api/v1/products")]
public IActionResult GetProductsV1()
{
    // Logic for version 1
}

// API v2
[Route("api/v2/products")]
public IActionResult GetProductsV2()
{
    // Logic for version 2
}
Bad Example
// Bad
// No versioning
[Route("api/products")]
public IActionResult GetProducts()
{
    // Logic without versioning
}
Important
Document Version Changes

Maintain a changelog to document changes, bug fixes, and updates for each version.

Good Example
// Good
// Changelog
// Version 1.0.0 - Initial release
// Version 1.1.0 - Added feature X
// Version 1.1.1 - Fixed bug Y
Bad Example
// Bad
// No changelog
// Users are unaware of changes and updates
Critical
Deprecate Old Versions Gracefully

Provide clear deprecation notices and timelines for phasing out old versions.

Good Example
// Good
// Deprecation notice
// API v1 will be deprecated on 2023-12-31
// Please migrate to API v2
Bad Example
// Bad
// No deprecation notice
// Users are caught off guard by sudden changes
Important
Implement Feature Toggles

Use feature toggles to manage the release of new features without deploying a new version.

Good Example
// Good
public class FeatureToggle
{
    public bool IsFeatureXEnabled { get; set; }

    public void ToggleFeatureX()
    {
        // Logic to enable/disable feature X
    }
}
Bad Example
// Bad
// No feature toggles
// New features require a full deployment
Critical
Use Version Control Branching Strategies

Adopt branching strategies like Git Flow or trunk-based development to manage version control effectively.

Good Example
// Good
// Git Flow
// - master: production-ready code
// - develop: latest development changes
// - feature branches: new features
Bad Example
// Bad
// No branching strategy
// Code changes are made directly to the main branch

Additional Resources

Deepen your understanding with these comprehensive guides

C# Coding Conventions
Official Microsoft guidelines for C# code style
Design Patterns in C#
Common design patterns and their C# implementations
Performance Guidelines
Optimize your C# applications for better performance