.NET & C# Development · Lesson 145 of 229
Complete Scenarios & Deep Dives (Cegal-style)
This is the complete senior .NET interview guide — scenario questions, deep technical dives, and realistic follow-ups for enterprise roles (e.g. Cegal, healthcare, SaaS).
Golden rule: Seniors explain why, when, tradeoffs, and production impact — not definitions alone.
Your edge: Tie answers to real systems — BuildTrace, healthcare compliance, multi-tenant SaaS, Azure deployments, EF Core tuning, SignalR, background jobs.
Related: High-Priority Topics (7 core areas) · Senior Q&A Q81–Q250
How to Answer Like a Senior
| Weak | Senior | |---|---| | "Redis improves performance." | "Redis cuts DB load for hot reads, but I plan invalidation and accept eventual consistency on cached data." | | "Use microservices." | "I'd start modular monolith unless team boundaries or independent scaling justify distributed ops cost." | | "await makes code faster." | "await improves scalability by not blocking thread-pool threads during I/O — it doesn't speed up CPU work." |
Always structure scenario answers: observe → hypothesize → measure → fix → prevent.
Part A — Real Interview Scenarios
1. API Suddenly Slow After Large Customer Onboarding
Question: "Your API becomes slow in production after onboarding a large customer. How do you investigate and fix it?"
What they want: Structured debugging, production mindset, database + cloud monitoring.
Investigation (systematic)
- Confirm scope — All endpoints or one tenant? One region? Started after deploy or customer go-live?
- Monitoring first
- Azure Application Insights: request duration (p50/p95/p99), failure rate, dependency calls
- SQL: slow query log, DTU/CPU, connection pool exhaustion
- App Service: CPU, memory, thread pool queue length, autoscale events
- Correlate — Spike in traffic vs. one slow dependency vs. noisy neighbor on shared DB
Common root causes (large tenant)
| Cause | Signal | Fix |
|---|---|---|
| N+1 queries | Many SQL round-trips per request | Include, projection, split queries |
| Missing indexes | Slow queries on new data volume | Index FKs, filter columns, composite indexes |
| Full entity loads | Large JSON payloads | DTO projection, pagination |
| No tenant filter | Cross-tenant scans | Global query filter + index on TenantId |
| Connection pool saturation | Timeouts under load | Pool size, shorter transactions, read replicas |
| Sync-over-async | Thread pool starvation | Remove .Result / .Wait() |
Fixes (with tradeoffs)
- Pagination — Required for lists; cursor pagination at scale (offset slow on deep pages).
- Caching (Redis) — Hot reads; plan TTL + invalidation on writes.
AsNoTracking()— Read endpoints only; not on update paths.- Async all the way — DB and HTTP calls async; no blocking.
- Query optimization —
EXPLAIN/ execution plans;.ToQueryString()in staging. - Scale — Horizontal App Service instances, read replica for reports, CDN for static assets.
Senior closing line
"I'd baseline p95 latency before and after each change, document the bottleneck in App Insights or SQL, fix the highest-impact item first — usually database round-trips or missing indexes for a new high-volume tenant — then add alerts so we catch regression before the next customer onboard."
2. Microservices vs Monolith
Question: "Would you always use microservices?"
Answer: No.
| Choose monolith / modular monolith when | Choose microservices when | |---|---| | Small team, fast delivery | Independent scaling per service | | Shared domain, one deployment unit | Separate teams per bounded context | | Simpler ops, lower overhead | Different release cadences | | Early product — unknown boundaries | Large domain, clear boundaries proven |
Senior add-ons: Distributed tracing (OpenTelemetry), message queues for async boundaries, eventual consistency (not distributed transactions everywhere), operational cost (deployments, monitoring, failures).
"At BuildTrace-scale SaaS I'd often start with a modular monolith — clear modules, separate projects — and extract services only when scaling or team structure demands it."
3. Two Users Update the Same Record
Question: "Two users update the same record at the same time. How do you handle it?"
Optimistic concurrency (default for most business apps)
public class CaseFile
{
public int Id { get; set; }
public string Status { get; set; } = null!;
[Timestamp]
public byte[] RowVersion { get; set; } = null!;
}- User A and B load same row (same
RowVersion). - A saves first → DB updates row, new
RowVersion. - B saves → EF throws
DbUpdateConcurrencyException. - API returns 409 Conflict with message to refresh and retry.
Why optimistic: Conflicts are rare; no long DB locks; scales better than pessimistic locking on every read.
Alternatives: Pessimistic lock (UPDLOCK) for high-contention resources (inventory, seat booking). Retry with Polly for transient deadlocks — not for concurrency conflicts (user must merge).
4. Scalable Cloud Architecture for File Uploads
Question: "Design a scalable architecture for file uploads."
React SPA
→ ASP.NET Core API (validate size/type, auth)
→ Generate SAS URL (short-lived) OR server-side upload stream
→ Azure Blob Storage (private container)
→ Queue message (Service Bus / Storage Queue)
→ Background worker: virus scan, thumbnails, metadata
→ SQL: file metadata, tenantId, status, blob path
→ CDN (optional) for public/signed delivery| Concern | Approach | |---|---| | Security | SAS tokens, least privilege, no public write container | | Large files | Chunked upload, client direct-to-blob | | Processing | Async queue — API returns 202 + job id | | Compliance | GDPR/HIPAA: region, encryption at rest, audit log, retention | | Resilience | Retry policies, dead-letter queue, idempotent handlers | | Cost | Lifecycle rules (cool/archive), CDN only where needed |
5. Works Locally, Fails in Azure
Question: "Production works locally but fails in Azure. What do you check?"
- Environment variables / Key Vault — Missing
CLERK_*, connection strings, API keys (especiallyNEXT_PUBLIC_*baked at build time for frontends). - Connection strings — Firewall rules, Azure SQL vs local SQL.
- CORS — Production origin not allowed.
- Docker / Linux — Case-sensitive paths; line endings; listen on
0.0.0.0andPORT. - Managed Identity — Permissions to Blob, Key Vault, SQL.
- Networking — Private endpoints, VNet integration, outbound rules.
- Logs — App Insights, Kudu logs,
stdoutin container. - HTTPS / reverse proxy — Forwarded headers (
X-Forwarded-Proto) for redirects and cookies.
"Login blank on production but fine locally is often missing Clerk publishable key at build time, not just runtime app settings."
6. React + .NET Communication
Question: "How do you structure frontend/backend communication?"
- OpenAPI/Swagger — Contract; generate TypeScript client or hand-maintained types.
- DTOs — API models ≠ domain entities; never expose EF entities.
- Versioning — URL or header when breaking changes; additive changes without version bump.
- Auth — JWT access (short) + refresh (httpOnly cookie or secure storage); silent refresh flow.
- Errors — RFC 7807 ProblemDetails; consistent shape; correlation id header.
- Resilience — Retries on idempotent GETs only; exponential backoff.
- TanStack Query — Server state, caching, stale-while-revalidate, optimistic updates where safe.
7. Difficult Production Incident (STAR)
Use STAR: Situation → Task → Action → Result.
Example angles from your background:
| Story | Situation | Action | Result | |---|---|---|---| | Healthcare slow API | Reports timing out after data growth | Found N+1 + missing index on tenant filter | p95 dropped 80%; added SQL alert | | Race condition | Duplicate records under concurrent sync | Optimistic concurrency + idempotent API | Conflicts surfaced as 409; support trained | | Deploy failure | App Service 500 after release | Missing env var; fixed pipeline + Key Vault | Rollback procedure + pre-deploy smoke test | | Third-party outage | Payment webhook delays | Queue + retry + manual reconciliation dashboard | No lost orders; SLA documented |
Always mention: impact, communication (stakeholders), fix, prevention (monitoring, tests, runbook).
8. Why Clean Architecture?
Benefits: Separation of concerns, testability, domain independent of EF/UI, clearer boundaries.
Senior balance: "I use Clean Architecture when domain complexity and long maintenance justify the ceremony. For small CRUD internal tools, vertical slices or a well-structured monolith is faster without sacrificing quality."
Layers (typical): Domain → Application → Infrastructure → API. Dependencies point inward.
9. How Do You Secure APIs?
| Layer | Practice | |---|---| | Transport | HTTPS everywhere | | AuthN | JWT validation (issuer, audience, expiry, signing key rotation) | | AuthZ | RBAC, policies, resource-based (owner/tenant) | | Input | Validation (FluentValidation), parameterized queries | | Abuse | Rate limiting per user/IP/tenant | | Secrets | Key Vault, never in repo; managed identity | | Ops | Audit logging, least privilege, OWASP Top 10 awareness |
Enterprise (Cegal-style): tenant isolation, audit trails, secrets rotation, no sensitive data in logs.
10. How Do You Use AI in Development?
- Architecture brainstorming, boilerplate, tests, docs, debugging hints, code review support.
- Always validate AI output — security, edge cases, performance, licensing.
- Never paste secrets into public tools; use for productivity, not blind production commits.
Questions You Should Ask Them
- How is cloud architecture structured today?
- How do teams handle deployments and DevOps ownership?
- What are the biggest scaling challenges right now?
- How much architectural ownership do senior developers have?
- How do you balance technical debt vs delivery?
- Are teams organized by domain or platform?
- How are production incidents handled (on-call, postmortems)?
Part B — Middleware Pipeline (Deep Dive)
Full request path
Browser → Reverse proxy (Nginx/IIS) → Kestrel → Middleware → Routing
→ Authentication → Authorization → Endpoint → DB → ResponseKestrel — ASP.NET Core web server. Production: usually behind reverse proxy for SSL, load balancing, filtering.
Middleware — Components that inspect/modify/short-circuit requests. Runs in order on the way in, reverse order on the way out (like nested layers).
app.Use(async (context, next) =>
{
// BEFORE
await next(context);
// AFTER — can modify response headers here
});Short-circuiting
Stop pipeline without calling next — used for failed auth, rate limits, maintenance mode, cache hits. Performance: don't hit DB if request already invalid.
Correct order
app.UseExceptionHandler();
app.UseHttpsRedirection();
app.UseStaticFiles(); // early — avoid auth on CSS/JS
app.UseRouting();
app.UseCors();
app.UseAuthentication(); // BEFORE authorization
app.UseAuthorization();
app.UseRateLimiter();
app.MapControllers();Classic question: Why auth before authorization? — Authorization needs HttpContext.User populated by authentication.
Use vs Run vs Map
| API | Behavior |
|---|---|
| Use | Calls next middleware |
| Run | Terminal — no next |
| Map | Branch pipeline by path |
Exception middleware
Centralize error handling → ProblemDetails, log server-side, never expose stack traces in production. Place early to wrap entire pipeline.
Middleware vs Filters
| | Middleware | Filters | |---|---|---| | Scope | Entire ASP.NET pipeline | MVC/actions | | Use for | Logging, auth, CORS, exceptions | Action validation, result formatting |
HttpContext rules
- Not thread-safe — don't store in singleton.
- Don't use in fire-and-forget after request ends.
- Background work: create scope via
IServiceScopeFactory.
Production debug: "Auth randomly fails"
Check: middleware order → JWT config → clock skew → HTTPS/forwarded headers → proxy stripping Authorization header.
Part C — Dependency Injection & Lifetimes
Why DI?
Separates creation from usage → testability, loose coupling, explicit dependencies via constructor injection.
Three lifetimes
| Lifetime | Created | Typical use |
|---|---|---|
| Singleton | Once per app | Logger, cache, config (stateless + thread-safe) |
| Scoped | Once per request | DbContext, unit of work |
| Transient | Every resolve | Lightweight stateless helpers |
Why DbContext is scoped
One unit of work per HTTP request; change tracker consistent; connection returned after request. Not singleton — thread-unsafe, memory leak across requests.
Captive dependency (VERY COMMON)
// WRONG
builder.Services.AddSingleton<CacheService>();
builder.Services.AddScoped<AppDbContext>();
// CacheService(AppDbContext db) → DbContext lives forever → DISPOSED/STALE BUGSFix: IServiceScopeFactory or IDbContextFactory<T> in singleton/background code.
BackgroundService + DbContext
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
// use db
}Anti-patterns
- Service locator —
GetService<T>()hidden in business logic. - Circular dependencies — refactor boundaries, mediator, events.
- Mutable state in singleton — race conditions.
Part D — Async, Await & Concurrency
Mental model
await yields the thread during I/O — thread pool serves other requests. Does not make CPU work faster.
Concurrency vs parallelism
- Async/concurrency — I/O-bound (DB, HTTP, files).
- Parallelism — CPU-bound (
Parallel.ForEach, multiple cores).
.Result / .Wait() — dangerous
Blocks thread pool thread; can deadlock (especially with sync context); hurts scalability under load. Fix: async all the way.
Task.WhenAll
Independent I/O in parallel — not sequential awaits. Don't share one DbContext across parallel tasks.
CancellationToken
Pass through to DB/HTTP — stop work when client disconnects; saves resources.
Race conditions
Use: transactions, optimistic concurrency, locks (sparingly in web), atomic DB operations.
Fire-and-forget
_ = DoWorkAsync() — exceptions lost. Prefer BackgroundService or queue.
When async hurts
- Tiny CPU work with async overhead.
- Too many concurrent DB calls (exhaust pool).
Task.Runin ASP.NET for normal request work (usually unnecessary).
Part E — EF Core Performance (Critical)
IQueryable vs IEnumerable
- IQueryable — builds SQL; filters run in database.
- IEnumerable — executes in memory — danger:
AsEnumerable()beforeWhereloads entire table.
AsNoTracking
Read-only queries — less memory, faster. Don't use when you need to update same entities in same request without reload.
N+1
1 query for parents + N for children. Fix: Include, projection, explicit batch query, split query.
// GOOD — projection
await _db.Orders
.Where(o => o.TenantId == id)
.Select(o => new OrderDto { Id = o.Id, Total = o.Lines.Sum(l => l.Price) })
.ToListAsync(ct);Include / split queries
Multiple Include on collections → cartesian explosion. Use AsSplitQuery() for large graphs.
Pagination
- Offset — simple; slow for deep pages (
OFFSET 100000). - Cursor —
WHERE Id > @last ORDER BY Id LIMIT 20— stable at scale.
Indexes
Index: foreign keys, WHERE, ORDER BY, composite (TenantId, CreatedAt DESC). Check execution plans.
Raw SQL
When: complex reports, bulk updates (ExecuteUpdateAsync), DB-specific optimizations. Always parameterized.
Detect N+1
SQL logging, MiniProfiler, App Insights dependency count, integration tests asserting query count.
Part F — Question Banks (Senior Answers)
Architecture
Scalable API platform — Stateless API behind load balancer, Redis cache, async workers, read replicas, API versioning, rate limits, OpenTelemetry.
Split microservices — When independent scale/deploy/team boundaries outweigh ops complexity.
Prevent tight coupling — Interfaces at boundaries, events for cross-module communication, no shared mutable singletons.
Large .NET solution — src/Domain, Application, Infrastructure, Api; feature folders or vertical slices inside Application.
Clean Architecture everywhere? — No; match complexity to project.
Performance
Slow query — Execution plan, N+1, missing index, tracking overhead, network payload.
High CPU — Profiling, sync-over-async, tight loops, excessive allocations.
Memory leaks — Event handlers not unsubscribed, static caches growing, undisposed IDisposable, EF tracking too many entities.
Detect N+1 — Log SQL count per request; App Insights dependencies.
Cloud / Azure
Deploy .NET — App Service or containers (ACI/AKS); GitHub Actions; Key Vault; App Insights.
Docker vs App Service — App Service: managed, easy; Docker: full control, portable.
Zero-downtime — Deployment slots, health checks, backward-compatible migrations.
Secrets — Key Vault + managed identity; never in git.
Scale APIs — Horizontal scale, Redis, DB read replicas, queue heavy work.
DevOps
CI/CD — Build, test, SAST, deploy staging, smoke test, deploy prod, migration step, rollback plan.
Rollback — Redeploy previous slot/image; DB migrations must be backward compatible.
Monitoring — RED metrics (rate, errors, duration), logs with correlation id, alerts on SLO breach.
Database
Raw SQL vs EF — EF for most CRUD; SQL for reports, bulk, complex tuning.
Offset vs cursor — Offset for small/admin; cursor for high-volume feeds.
Transactions — Short boundaries; avoid long TX with HTTP calls inside.
Security
JWT flow — Login → access token (short) + refresh → API validates signature/claims → refresh rotates.
OAuth — Delegated auth; your API is resource server.
RBAC — Roles in claims; policies in ASP.NET Core.
SQL injection — Parameterized queries; never string concat SQL.
Part G — Background Services & Cloud Config
Background processing
| Tool | When |
|---|---|
| BackgroundService | In-process periodic work |
| Hangfire | Jobs dashboard, retries, cron |
| Quartz | Complex scheduling |
| Service Bus | Multi-instance, reliable delivery |
Graceful shutdown — respect CancellationToken; don't start unbounded work on shutdown.
Configuration
Precedence (later wins): appsettings.json → appsettings.{Env}.json → environment variables → Key Vault.
| Type | Use |
|---|---|
| IOptions<T> | Static config at startup |
| IOptionsSnapshot<T> | Per-request refresh |
| IOptionsMonitor<T> | Singleton + change callbacks |
Part H — API Design (Summary)
REST nouns/verbs, correct status codes, validation at boundary, ProblemDetails errors, JWT + refresh, rate limiting, OpenAPI for contract.
Part I — Cegal / Enterprise Fit (Your Profile)
You match: .NET backend, Azure, enterprise/compliance, full-stack, Docker, scalable APIs, production incidents.
Strength: Real architecture experience — not tutorials.
Interview flow (typical): Intro → past projects → deep .NET → architecture → cloud/DevOps → scenario → team fit.
Part J — Preparation Priority
Tier 1 (master first)
- Middleware pipeline
- DI lifetimes
- EF Core performance
- Async/concurrency
- API security
Tier 2
- Azure architecture
- Docker/Linux
- Clean Architecture
- Logging/monitoring
- CI/CD
Tier 3
- Distributed systems / messaging
- Kubernetes basics
- Advanced caching
Final Reminder
Practice aloud with your stories. When they ask about slow APIs, mention Application Insights and a real index you added. When they ask concurrency, mention RowVersion and 409 responses. That is what separates senior from mid-level.