Introduction
In this article, we will learn about 𝗪𝗲𝗯 𝗔𝗣𝗜 𝗔𝗻𝘁𝗶-𝗣𝗮𝘁𝘁𝗲𝗿𝗻𝘀 𝗧𝗵𝗮𝘁 𝗕𝗿𝗲𝗮𝗸 𝗬𝗼𝘂𝗿 .𝗡𝗘𝗧 𝗔𝗽𝗽𝘀 𝗶𝗻 𝗣𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻.
Building a Web API that works on your machine is easy. Building one that survives production traffic, failures, security threats, and scale is a different challenge entirely
Here are common ASP.NET Core Web API anti-patterns that often cause outages, performance degradation, and maintenance nightmares.
Let's get started.
1. Returning 200 OK for Everything
Anti-Pattern
return Ok(new
{
Success = false,
Message = "User not found"
});
Why It's Bad
Clients cannot distinguish between successful and failed requests using HTTP semantics.
Better Approach
return NotFound("User not found");
Use proper status codes:
2. Catching Every Exception Globally and Hiding Details
Anti-Pattern
try
{
...
}
catch(Exception)
{
return StatusCode(500);
}
Problems
Better Approach
Use centralized exception middleware:
app.UseExceptionHandler();
Log exceptions with:
ILogger<T>
Return standardized problem details.
return Problem(
title: "Unexpected error occurred",
statusCode: 500);
3. Synchronous Database Calls
Anti-Pattern
var users = _context.Users.ToList();
Why It's Dangerous
Under load:
Better Approach
var users = await _context.Users.ToListAsync();
``
Use async end-to-end.
4. Fat Controllers
Anti-Pattern
[HttpPost]
public IActionResult CreateOrder(...)
{
// validation
// business logic
// database updates
// notifications
// email sending
}
Problems
Better Approach
await _orderService.CreateOrderAsync(request);
Keep controllers thin.
5. Exposing EF Core Entities Directly
Anti-Pattern
return Ok(customerEntity);
Problems
Leaks internal structure
Serialization issues
Security risks
Circular references
Better Approach
Use DTOs:
public record CustomerDto(
int Id,
string Name,
string Email);
``
Map entities to DTOs.
6. Overfetching Data
Anti-Pattern
var users = await _context.Users
.Include(x => x.Orders)
.Include(x => x.Payments)
.Include(x => x.Addresses)
.ToListAsync();
Problems
Huge payloads
Slow SQL
Memory pressure
Better Approach
Project only required fields:
var users = await _context.Users
.Select(u => new UserListDto
{
Id = u.Id,
Name = u.Name
})
.ToListAsync();
7. Missing API Versioning
Anti-Pattern
Deploying breaking changes directly.
/api/customers
Result
Existing consumers suddenly fail.
Better Approach
/api/v1/customers
/api/v2/customers
Or use header-based versioning.
8. No Request Validation
Anti-Pattern
public async Task<IActionResult> Create(UserRequest request)
{
// directly process
}
Problems
Better Approach
Use:
[ApiController]
and FluentValidation:
RuleFor(x => x.Email)
.NotEmpty()
.EmailAddress();
9. Ignoring Cancellation Tokens
Anti-Pattern
public async Task<IActionResult> Get()
{
await _service.ProcessAsync();
}
Problem
Work continues even after:
Browser closes
Mobile app disconnects
Load balancer times out
Better Approach
public async Task<IActionResult> Get(
CancellationToken ct)
{
await _service.ProcessAsync(ct);
}
10. Logging Too Little or Too Much
Too Little
_logger.LogError("Error");
No context.
Too Much
_logger.LogInformation(JsonSerializer.Serialize(request));
May expose:
Better Approach
Structured logging:
_logger.LogInformation(
"Creating order {OrderId} for customer {CustomerId}",
orderId,
customerId);
11. No Rate Limiting
Anti-Pattern
API accepts unlimited requests.
Risks
DDoS attacks
Resource exhaustion
Database overload
Better Approach (.NET 7+)
builder.Services.AddRateLimiter(...);
app.UseRateLimiter();
Protect critical endpoints.
12. Ignoring Health Checks and Observability
Anti-Pattern
You only discover problems after customers complain.
Missing Components
Health checks
Metrics
Tracing
Dashboards
Better Approach
builder.Services.AddHealthChecks();
app.MapHealthChecks("/health");
Add:
OpenTelemetry
Application Insights
Prometheus
Grafana
for proactive monitoring.
Production-Ready API Checklist
✅ Proper HTTP status codes
✅ Global exception handling
✅ Async all the way
✅ Thin controllers
✅ DTOs instead of entities
✅ Request validation
✅ API versioning
✅ Cancellation tokens
✅ Structured logging
✅ Rate limiting
✅ Health checks
✅ Observability & tracing
The majority of production API issues in .NET applications are not caused by complex algorithms. They're caused by these architectural and operational anti-patterns that quietly accumulate until traffic, scale, or failures expose them. Fixing them early dramatically improves reliability, performance, and maintainability.
Conclusion
In this article, I have tried to cover Difference Between Controller and ControllerBase in ASP.NET Core.