
Development Workflow
- 7 installs
- 4 repo stars
- Updated June 18, 2026
- doubleslashse/claude-marketplace
Follow a general .NET development workflow when implementing features, fixing bugs, or refactoring C# code.
About
Describes a general .NET workflow for implementing features, fixing bugs, and refactoring. A developer uses it as a baseline process when working in a C# codebase.
- End-to-end feature, bugfix, and refactor workflow
- Targets .NET codebases
Development Workflow by the numbers
- 7 all-time installs (skills.sh)
- Ranked #114 of 153 .NET & C# skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/doubleslashse/claude-marketplace --skill development-workflowAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7 |
|---|---|
| repo stars | ★ 4 |
| Last updated | June 18, 2026 |
| Repository | doubleslashse/claude-marketplace ↗ |
What it does
Follow a general .NET development workflow when implementing features, fixing bugs, or refactoring C# code.
Files
.NET Development Workflow
Workflow Overview
┌─────────────────────────────────────────────────────────────────┐
│ DEVELOPMENT WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ Understand │ Read requirements, explore codebase │
│ │ Task │ │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Implement │ Write code following patterns │
│ │ Changes │ │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Validate │────▶│ Report │ │
│ │ Build/Test/ │ │ Results │ │
│ │ Analyze │ │ │ │
│ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌──────────┐ │
│ │ PASS? │───NO───▶│ Fix │ │
│ └─────────┘ │ Issues │ │
│ │ └──────────┘ │
│ │ │ │
│ YES │ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ Ready to │◀──────────┘ │
│ │ Commit │ (re-validate) │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Phase 1: Understand the Task
Feature Implementation
1. Read the feature requirements/user story 2. Identify affected components 3. Check existing patterns in codebase 4. Plan the implementation approach
Bug Fix
1. Reproduce the bug 2. Identify root cause 3. Find related code 4. Plan the fix
Refactoring
1. Understand current implementation 2. Identify what needs to change 3. Ensure test coverage exists 4. Plan incremental changes
Phase 2: Implement Changes
Follow Existing Patterns
// Find existing patterns
// Look for similar implementations in the codebase
// Follow established conventions
// Example: If services follow this pattern
public class ExistingService : IExistingService
{
private readonly IRepository _repository;
private readonly ILogger<ExistingService> _logger;
public ExistingService(IRepository repository, ILogger<ExistingService> logger)
{
_repository = repository;
_logger = logger;
}
}
// New service should follow same pattern
public class NewService : INewService
{
private readonly IRepository _repository;
private readonly ILogger<NewService> _logger;
public NewService(IRepository repository, ILogger<NewService> logger)
{
_repository = repository;
_logger = logger;
}
}Make Small, Incremental Changes
1. One logical change at a time 2. Build after each change to catch errors early 3. Run relevant tests frequently 4. Keep commits focused
Phase 3: Validate Changes
Validation Steps
# 1. Build (catch compilation errors)
dotnet build --no-incremental
# 2. Run tests (verify behavior)
dotnet test --no-build
# 3. Static analysis (code quality)
dotnet build /p:TreatWarningsAsErrors=true
dotnet format --verify-no-changesQuality Gates
| Gate | Requirement | Blocking |
|---|---|---|
| Build | 0 errors | Yes |
| Tests | 100% pass | Yes |
| Critical Warnings | 0 | No |
| All Warnings | < 10 | No |
Phase 4: Fix Issues
Build Errors
1. Read error message carefully 2. Go to the file and line indicated 3. Fix the issue 4. Rebuild to verify
Test Failures
1. Read the assertion failure 2. Check expected vs actual 3. Determine if test or code is wrong 4. Fix and re-run test
Analysis Warnings
1. Review each warning 2. Apply fix or suppress with justification 3. Use dotnet format for auto-fixable issues
Validation Before Commit
Checklist
- [ ]
dotnet buildsucceeds with no errors - [ ]
dotnet testpasses all tests - [ ] No new critical analyzer warnings
- [ ] Code follows existing patterns
- [ ] Changes are focused on the task
Commands
# Full validation
dotnet build --no-incremental && \
dotnet test --no-build && \
dotnet format --verify-no-changesBest Practices
Code Organization
// Group related code
// 1. Fields
private readonly IService _service;
// 2. Constructors
public MyClass(IService service) => _service = service;
// 3. Public methods
public void Execute() { }
// 4. Private methods
private void Helper() { }Error Handling
// Be specific with exceptions
public User GetUser(int id)
{
var user = _repository.Find(id);
if (user == null)
throw new EntityNotFoundException($"User {id} not found");
return user;
}
// Use guard clauses
public void Process(Request request)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentException.ThrowIfNullOrEmpty(request.Name);
// Main logic
}Async/Await
// Always use async suffix
public async Task<User> GetUserAsync(int id)
{
return await _repository.FindAsync(id);
}
// Don't block on async
// BAD
var user = GetUserAsync(id).Result;
// GOOD
var user = await GetUserAsync(id);Dependency Injection
// Register services
services.AddScoped<IUserService, UserService>();
services.AddSingleton<ICacheService, MemoryCacheService>();
services.AddTransient<IEmailSender, SmtpEmailSender>();
// Inject via constructor
public class UserController
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
}Common Patterns
See patterns.md for detailed implementation patterns.
.NET Development Patterns
Repository Pattern
// Interface
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(T entity);
}
// Implementation
public class Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
private readonly DbSet<T> _dbSet;
public Repository(DbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public async Task<T?> GetByIdAsync(int id)
=> await _dbSet.FindAsync(id);
public async Task<IEnumerable<T>> GetAllAsync()
=> await _dbSet.ToListAsync();
public async Task AddAsync(T entity)
=> await _dbSet.AddAsync(entity);
public async Task UpdateAsync(T entity)
=> _dbSet.Update(entity);
public async Task DeleteAsync(T entity)
=> _dbSet.Remove(entity);
}Service Layer Pattern
// Interface
public interface IOrderService
{
Task<Order> CreateOrderAsync(CreateOrderRequest request);
Task<Order?> GetOrderAsync(int id);
Task CancelOrderAsync(int id);
}
// Implementation
public class OrderService : IOrderService
{
private readonly IRepository<Order> _orderRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger<OrderService> _logger;
public OrderService(
IRepository<Order> orderRepository,
IUnitOfWork unitOfWork,
ILogger<OrderService> logger)
{
_orderRepository = orderRepository;
_unitOfWork = unitOfWork;
_logger = logger;
}
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
var order = new Order
{
CustomerId = request.CustomerId,
Items = request.Items.Select(i => new OrderItem
{
ProductId = i.ProductId,
Quantity = i.Quantity
}).ToList(),
Status = OrderStatus.Pending
};
await _orderRepository.AddAsync(order);
await _unitOfWork.SaveChangesAsync();
_logger.LogInformation("Order {OrderId} created", order.Id);
return order;
}
}Unit of Work Pattern
public interface IUnitOfWork : IDisposable
{
IRepository<Order> Orders { get; }
IRepository<Customer> Customers { get; }
Task<int> SaveChangesAsync();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public UnitOfWork(AppDbContext context)
{
_context = context;
Orders = new Repository<Order>(_context);
Customers = new Repository<Customer>(_context);
}
public IRepository<Order> Orders { get; }
public IRepository<Customer> Customers { get; }
public async Task<int> SaveChangesAsync()
=> await _context.SaveChangesAsync();
public void Dispose()
=> _context.Dispose();
}Result Pattern
public class Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
private Result(bool isSuccess, T? value, string? error)
{
IsSuccess = isSuccess;
Value = value;
Error = error;
}
public static Result<T> Success(T value)
=> new(true, value, null);
public static Result<T> Failure(string error)
=> new(false, default, error);
}
// Usage
public async Task<Result<Order>> CreateOrderAsync(CreateOrderRequest request)
{
if (request.Items.Count == 0)
return Result<Order>.Failure("Order must have at least one item");
var order = new Order { /* ... */ };
await _repository.AddAsync(order);
return Result<Order>.Success(order);
}Options Pattern
// Configuration class
public class EmailSettings
{
public const string SectionName = "Email";
public string SmtpHost { get; set; } = string.Empty;
public int SmtpPort { get; set; }
public string FromAddress { get; set; } = string.Empty;
}
// Registration
services.Configure<EmailSettings>(
configuration.GetSection(EmailSettings.SectionName));
// Usage
public class EmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> options)
{
_settings = options.Value;
}
}Factory Pattern
public interface INotificationFactory
{
INotification Create(NotificationType type);
}
public class NotificationFactory : INotificationFactory
{
private readonly IServiceProvider _serviceProvider;
public NotificationFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public INotification Create(NotificationType type) => type switch
{
NotificationType.Email => _serviceProvider.GetRequiredService<EmailNotification>(),
NotificationType.Sms => _serviceProvider.GetRequiredService<SmsNotification>(),
NotificationType.Push => _serviceProvider.GetRequiredService<PushNotification>(),
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
}Specification Pattern
public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria { get; }
List<Expression<Func<T, object>>> Includes { get; }
}
public abstract class Specification<T> : ISpecification<T>
{
public abstract Expression<Func<T, bool>> Criteria { get; }
public List<Expression<Func<T, object>>> Includes { get; } = new();
protected void AddInclude(Expression<Func<T, object>> include)
=> Includes.Add(include);
}
// Usage
public class ActiveOrdersSpec : Specification<Order>
{
public override Expression<Func<Order, bool>> Criteria
=> o => o.Status != OrderStatus.Cancelled && o.Status != OrderStatus.Completed;
public ActiveOrdersSpec()
{
AddInclude(o => o.Customer);
AddInclude(o => o.Items);
}
}Mediator Pattern (MediatR)
// Query
public record GetOrderQuery(int Id) : IRequest<Order?>;
public class GetOrderHandler : IRequestHandler<GetOrderQuery, Order?>
{
private readonly IRepository<Order> _repository;
public GetOrderHandler(IRepository<Order> repository)
{
_repository = repository;
}
public async Task<Order?> Handle(GetOrderQuery request, CancellationToken ct)
{
return await _repository.GetByIdAsync(request.Id);
}
}
// Command
public record CreateOrderCommand(int CustomerId, List<OrderItemDto> Items) : IRequest<Order>;
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Order>
{
public async Task<Order> Handle(CreateOrderCommand request, CancellationToken ct)
{
// Implementation
}
}Guard Clauses
public static class Guard
{
public static void AgainstNull<T>(T? value, string paramName) where T : class
{
if (value is null)
throw new ArgumentNullException(paramName);
}
public static void AgainstEmpty(string? value, string paramName)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Value cannot be empty", paramName);
}
public static void AgainstNegative(int value, string paramName)
{
if (value < 0)
throw new ArgumentOutOfRangeException(paramName, "Value cannot be negative");
}
}
// Usage
public void Process(Order order, int quantity)
{
Guard.AgainstNull(order, nameof(order));
Guard.AgainstNegative(quantity, nameof(quantity));
// Main logic
}Decorator Pattern
// Interface
public interface INotificationService
{
Task SendAsync(Notification notification);
}
// Base implementation
public class EmailNotificationService : INotificationService
{
public async Task SendAsync(Notification notification)
{
// Send email
}
}
// Decorator
public class LoggingNotificationDecorator : INotificationService
{
private readonly INotificationService _inner;
private readonly ILogger<LoggingNotificationDecorator> _logger;
public LoggingNotificationDecorator(
INotificationService inner,
ILogger<LoggingNotificationDecorator> logger)
{
_inner = inner;
_logger = logger;
}
public async Task SendAsync(Notification notification)
{
_logger.LogInformation("Sending notification to {Recipient}", notification.Recipient);
await _inner.SendAsync(notification);
_logger.LogInformation("Notification sent successfully");
}
}
// Registration
services.AddScoped<EmailNotificationService>();
services.AddScoped<INotificationService>(sp =>
new LoggingNotificationDecorator(
sp.GetRequiredService<EmailNotificationService>(),
sp.GetRequiredService<ILogger<LoggingNotificationDecorator>>()));