Sitemap
Level Up Coding

Coding tutorials and news. The developer homepage gitconnected.com && skilled.dev && levelup.dev

Member-only story

Command Pattern in .NET C#: From undo buttons to queued, idempotent commands (2026)

--

Imagine developing the back-office of an e-commerce site. Every day, the operators change prices, launch discounts on whole categories and cancel orders on behalf of customers. The first version is a service with one method per operation:

// Naive approach - What NOT to do
public class BackOfficeService(
IProductRepository products, IOrderRepository orders, IPaymentGateway payments)
{
public async Task ChangePriceAsync(Guid productId, decimal newPrice)
{
var product = await products.FindAsync(productId);
product!.Price = newPrice; // the old price is gone forever
await products.SaveAsync(product);
}

public async Task CancelOrderAsync(Guid orderId)
{
var order = await orders.FindAsync(orderId);
await payments.RefundAsync(order!.PaymentId, order.Total); // retried after a timeout? Two refunds
order.Status = OrderStatus.Cancelled;
await orders.SaveAsync(order);
}

// ... ApplyCategoryDiscountAsync: 5,000 products, inside the HTTP request
}

Then the requests arrive. An operator types 1.79 instead of 17.90 and asks for an Undo button. The discount on 5,000 products times out in the browser. The auditors want to know who changed a price last Tuesday. And one morning a customer gets two refunds, because the gateway answered late and the operator clicked again.

--

--

Emanuele Longo
Emanuele Longo

Written by Emanuele Longo

.NET Software Developer driven by clean architecture and purposeful design.