C# Coding Standard

C# coding standard for Cadtastic Solutions.

View the Project on GitHub Cadtastic-Solutions/C-Sharp-Coding-Standard

Monolithic Project Structure

Purpose

This standard defines an organized, maintainable structure for single-project applications that balances simplicity with good architectural practices.

Project Structure

ProjectName/                    # Project root
├── Abstractions/              # [Required] Core abstractions
│   ├── Interfaces/            # Interfaces defining contracts
│   └── Base/                  # Base/abstract classes
│
├── Models/                    # [Required] Data models
│   ├── Entities/             # Database entities
│   ├── DTOs/                 # Data transfer objects
│   ├── Enums/                # Enumeration types
│   └── ViewModels/           # UI view models
│
├── Services/                  # [Required] Business logic
│   ├── Interfaces/           # Service contracts
│   └── Implementations/      # Service implementations
│
├── Data/                     # [Required] Data access
│   ├── Context/              # Database context
│   ├── Repositories/         # Data access logic
│   ├── Configurations/       # Entity configurations
│   └── Migrations/           # Database migrations
│
├── Utilities/                # [Optional] Helper classes
│   ├── Extensions/           # Extension methods
│   ├── Helpers/             # Helper classes
│   └── Constants/           # Constant values
│
├── Features/                 # [Required] Feature modules
│   ├── Users/               # User management feature
│   │   ├── Controllers/     # Feature controllers
│   │   ├── Views/          # Feature views
│   │   └── Services/       # Feature-specific services
│   └── Products/           # Product management feature
│       ├── Controllers/    
│       ├── Views/
│       └── Services/
│
├── wwwroot/                 # [Web Only] Static files
│   ├── css/
│   ├── js/
│   └── lib/
│
├── Views/                   # [MVC Only] Shared views
│   └── Shared/             # Shared view components
│
├── docs/                    # [Required] Documentation
│   ├── index.md
│   ├── getting-started/
│   ├── guides/
│   └── api/
│
├── build/                   # [Optional] Build files
├── .gitattributes          # [Required] Git attributes
├── .gitignore              # [Required] Git ignore rules
├── README.md               # [Required] Project overview
└── LICENSE.txt             # [Required] License information

Implementation Guidelines

1. Feature Organization

// Features/Users/Controllers/UserController.cs
public class UserController : Controller
{
    private readonly IUserService _userService;
    
    public async Task<IActionResult> List()
    {
        var users = await _userService.GetAllAsync();
        return View(users);
    }
}

// Features/Users/Services/UserService.cs
public class UserService : IUserService
{
    private readonly ApplicationDbContext _context;
    
    public async Task<List<UserDto>> GetAllAsync()
    {
        var users = await _context.Users.ToListAsync();
        return users.Select(u => u.ToDto()).ToList();
    }
}

2. Abstractions

// Abstractions/Interfaces/IRepository.cs
public interface IRepository<T> where T : class
{
    Task<T> GetByIdAsync(int id);
    Task<List<T>> GetAllAsync();
    Task AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(int id);
}

// Abstractions/Base/BaseEntity.cs
public abstract class BaseEntity
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

3. Models Organization

// Models/Entities/User.cs
public class User : BaseEntity
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }
}

// Models/DTOs/UserDto.cs
public class UserDto
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
}

// Models/ViewModels/UserViewModel.cs
public class UserViewModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public List<string> Roles { get; set; }
}

4. Data Access

// Data/Context/ApplicationDbContext.cs
public class ApplicationDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    
    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
    }
}

// Data/Repositories/UserRepository.cs
public class UserRepository : IRepository<User>
{
    private readonly ApplicationDbContext _context;
    
    public async Task<User> GetByIdAsync(int id)
    {
        return await _context.Users.FindAsync(id);
    }
}

5. Service Layer

// Services/Interfaces/IUserService.cs
public interface IUserService
{
    Task<UserDto> GetByIdAsync(int id);
    Task<List<UserDto>> GetAllAsync();
    Task<UserDto> CreateAsync(CreateUserDto dto);
}

// Services/Implementations/UserService.cs
public class UserService : IUserService
{
    private readonly IRepository<User> _repository;
    
    public async Task<UserDto> GetByIdAsync(int id)
    {
        var user = await _repository.GetByIdAsync(id);
        return user?.ToDto();
    }
}

Best Practices

1. Dependency Injection

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        
        // Register services
        builder.Services.AddScoped<IUserService, UserService>();
        builder.Services.AddScoped<IRepository<User>, UserRepository>();
    }
}

2. Feature Organization

3. Cross-Cutting Concerns

// Utilities/Extensions/ServiceCollectionExtensions.cs
public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddApplicationServices(
        this IServiceCollection services)
    {
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<IEmailService, EmailService>();
        return services;
    }
}

Documentation Requirements

Project-Level Documentation

Code Documentation

When to Evolve

Consider migrating to Clean Architecture when:

Additional Resources