1️⃣ Request Pipeline Architecture
High-Level Flow
Kestrel (Web Server) ↓ Middleware Pipeline (in order of registration) ↓ Routing ↓ Endpoint Execution (Controller / Minimal API) ↓ Response flows back up the pipeline
Important:
- Middleware executes in order registered
- Response flows in reverse order
- Order matters critically
Middleware Execution Model
If registered like:
app.Use(A); app.Use(B); app.Use(C); app.Run(D);
Execution order:
A → B → C → D C → B → A
Think nested wrappers.
2️⃣ Middleware vs Filters
Middleware
- HTTP-level
- Runs before MVC
- Applies globally
- Framework-agnostic
- Can short-circuit early
Use for:
- Authentication
- Authorization
- CORS
- Global exception handling
- Correlation IDs
- Logging
Filters (MVC only)
Run inside MVC pipeline.
Types:
- Authorization filters
- Resource filters
- Action filters
- Exception filters
- Result filters
Use when:
- Need access to action arguments
- Need ModelState
- Need controller context
Key Distinction
Middleware = HTTP layer
Filters = MVC layer
Global exception handling → Prefer middleware
3️⃣ Use vs Run vs Map
app.Use()
- Adds middleware
- Must call
await next()
- Can execute before and after next
app.Run()
- Terminal middleware
- Ends pipeline
- No next()
app.Map()
- Branches pipeline based on path
- Creates sub-pipeline
4️⃣ Dependency Injection (DI)
Lifetimes
Singleton
- One instance for app lifetime
- Created once at startup
Scoped
- One instance per request
Transient
- New instance every resolution
Dangerous Injection Rule
Singleton ❌ cannot depend on Scoped
Why?
- Scoped tied to request lifetime
- Singleton lives entire app lifetime
- Causes disposed object or lifetime leak
Correct Fix Pattern
Use
IServiceScopeFactory inside singleton:using var scope = _scopeFactory.CreateScope(); var service = scope.ServiceProvider.GetRequiredService<MyScopedService>();
5️⃣ Model Binding & Validation
Model Binding
- JSON → C# object
- Uses input formatter (System.Text.Json)
- Adds errors to ModelState
Validation
- Runs after successful binding
- Uses DataAnnotations
- Adds errors to ModelState
Automatic 400 Behavior
If
[ApiController] present:- Invalid ModelState → automatic 400
- Controller method not executed
Without
[ApiController]:- Must manually check ModelState
6️⃣ Customizing 400 Responses
Use:
builder.Services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { return new BadRequestObjectResult(...); }; });
Modern (.NET 8+):
builder.Services.AddProblemDetails();
Customize via:
options.CustomizeProblemDetails
7️⃣ Global Exception Handling
Preferred Approach
Middleware-based:
app.UseExceptionHandler();
Why?
- Catches everything
- Even before MVC executes
- Centralized logging
- Prevents stack trace leaks
Order Matters
Register early:
app.UseExceptionHandler(); app.UseAuthentication(); app.UseAuthorization();
8️⃣ Background Services
IHostedService
Manual lifecycle management.
BackgroundService
Preferred base class.
Override:
ExecuteAsync()
Handles cancellation wiring.
Distributed Scale Problem
Hosted services run per instance.
Scaling → multiple executions.
Solutions:
- Separate worker service
- Distributed lock (Redis / Blob lease)
- Hangfire (persistent scheduler)
- Azure Functions (Timer trigger)
9️⃣ HttpClient & IHttpClientFactory
Why Not Plain HttpClient?
- Socket exhaustion
- DNS refresh issues
- Connection pooling mismanagement
IHttpClientFactory Benefits
- Centralized configuration
- Connection pooling
- DNS refresh
- Resilience policies
- Typed clients
Typed Client Example
services.AddHttpClient<MyApiClient>();
Cleaner, testable, DI-friendly.
🔟 Logging
Log Levels
- Trace
- Debug
- Information
- Warning
- Error
- Critical
- None
Structured Logging
Good:
_logger.LogInformation("User {UserId} created order {OrderId}", userId, orderId);
Bad:
_logger.LogInformation($"User {userId} created order {orderId}");
Structured logs enable queryable properties.
1️⃣1️⃣ Observability
Logs
Discrete events.
Answer: What happened?
Metrics
Numerical aggregates.
Answer: How is system performing?
Examples:
- RPS
- CPU
- Latency
Traces
Distributed request flow.
Answer: Where did time go?
Tracks:
- Spans
- Dependencies
- Timing
- Correlation
1️⃣2️⃣ Correlation IDs
Pattern:
- Middleware generates or reads header
- Stored in logging scope
- Propagated via HTTP headers
Modern systems:
- Use Activity / OpenTelemetry
- Integrated with App Insights
1️⃣3️⃣ Thread Pool in ASP.NET Core
- No SynchronizationContext
- Runs on ThreadPool
- Async releases threads during I/O
- Blocking causes starvation
1️⃣4️⃣ Thread Pool Starvation
Caused by:
.Result
.Wait()
- Blocking I/O
- Overuse of Task.Run
Effect:
- Requests queue up
- Throughput collapse
1️⃣5️⃣ When NOT to Use Task.Run
Do NOT use for:
- Database calls
- HTTP calls
- I/O operations
ASP.NET Core already uses ThreadPool.
🎯 Final Interview Summary (Backend)
Strong ASP.NET Core candidate should understand:
- Request pipeline architecture
- DI lifetimes & scope safety
- Async scalability
- Middleware vs Filters
- Model binding internals
- Exception handling strategy
- Observability stack
- Background job scaling concerns
- HttpClient best practices
- Thread pool behavior