These are based on what’s commonly asked at product companies, fintech, SaaS, and cloud-heavy teams.
Task and ValueTask?Answer:Task is a reference type allocated on the heap. ValueTask is a struct designed to reduce allocations when an operation often completes synchronously.
Use ValueTask only when:
The method is hot-path
It frequently completes synchronously
You control both producer and consumer
Downsides:
More complex usage
Can only be awaited once unless converted to Task
Misuse can hurt performance
Rule: Default to Task. Use ValueTask only after profiling.
Answer:
.NET uses a generational GC:
Gen 0: Short-lived objects
Gen 1: Survivors from Gen 0
Gen 2: Long-lived objects
Large objects (>85KB) go to the LOH and are expensive to collect.
Server GC is optimised for throughput (used in ASP.NET), while Workstation GC is optimised for responsiveness.
Key optimisations:
Minimise allocations
Reuse objects
Avoid LOH allocations
async / await?Answer:
The compiler transforms the method into a state machine.
Execution runs synchronously until the first await
The thread is returned to the pool
Continuation runs when the awaited task completes
No new thread is created.
Common mistake:
Blocking with .Result or .Wait() → deadlocks (especially in ASP.NET).
Answer:
Requests pass through a chain of middleware.
Each middleware can:
Handle the request
Modify it
Short-circuit the pipeline
Order matters:
Exception handling → routing → auth → endpoints
Middleware is best for cross-cutting concerns; filters are better for MVC-specific logic.
Answer:
| Middleware | Filters |
|---|---|
| Global | MVC-only |
| Executes for all requests | Only controllers/actions |
| Runs before routing | Runs after routing |
| Good for logging/auth | Good for validation |
Answer:
Singleton: One instance per app
Scoped: One per request
Transient: New every resolution
Common pitfall:
Injecting Scoped into Singleton → memory leaks / runtime errors.
Answer:
Tracking: Change detection, higher memory usage
No-tracking: Faster reads, no change tracking
Use no-tracking for:
Read-only queries
APIs
Reporting
Answer:
Use AsNoTracking
Avoid lazy loading
Use projection (Select)
Add proper indexes
Use compiled queries
Use Dapper for complex queries
Answer:
Use async all the way
Avoid .Wait() / .Result
Avoid blocking locks with async code
Use ConfigureAwait(false) in libraries
lock vs SemaphoreSlim?Answer:
lock: Sync, in-memory, fast
SemaphoreSlim: Async-friendly, throttling
Use SemaphoreSlim for async APIs or rate limiting.
Answer:
Core rules:
Business logic is independent of frameworks
Dependencies point inward
Infrastructure is replaceable
Layers:
Domain
Application
Infrastructure
Presentation
Benefits:
Testability
Maintainability
Technology independence
Answer:
Monolith:
Simpler
Easier deployment
Faster development early
Microservices:
Independent scaling
Fault isolation
Higher complexity
Rule: Start monolith, extract services when scaling requires it.
Answer:
Use Polly:
Retry with backoff
Circuit breaker
Timeout
Never retry:
Non-idempotent operations
Authentication failures
Answer:
Backpressure prevents overload by slowing producers when consumers are overwhelmed.
Examples:
Bounded channels
Rate limiting
Queue depth monitoring
Answer:
Client authenticates
Server issues JWT
Client sends token in headers
Server validates signature and claims
JWT is stateless but:
Needs token expiration
Requires refresh strategy
Must be sent over HTTPS
Answer:
Unit: Fast, isolated, mocks dependencies
Integration: Real dependencies, slower, higher confidence
A senior balances both.
Answer:
Stabilise first
Rollback or mitigate
Communicate clearly
Root cause analysis
Prevent recurrence
No blame, focus on learning.
Answer:
Code reviews with explanation
Pair programming
Encourage ownership
Teach fundamentals, not shortcuts