There are roughly nine hundred lists of .NET interview questions on the internet and they are all more or less the same list. Define IDisposable. Explain async. What is change tracking in EF Core.
Fine. Useful, even. But at senior level that list is not your problem, because everyone who bothered to prepare has those answers. Question one is not a filter. It is a handshake.
The round turns on what comes next — the quiet follow-up asking what happened when you met the thing in production at an unreasonable hour. You cannot revise for that one. You either have the scar or you do not.
So: the questions, grouped by topic, each paired with the follow-up that usually decides it. Read the second one in every pair. That is the whole point.
1. C# language and runtime
Value types, disposal, closures, LINQ deferred execution
“What does IDisposable actually do, and when do you implement a finalizer?”
“Tell me about a leak you traced. What was holding the reference?”
The definition is memorizable. The leak is not. It is almost always an event handler nobody unsubscribed, a static cache quietly hoarding, or a closure holding half the object graph hostage. Anyone who has actually chased one names their tool unprompted — dotMemory, PerfView, a dump opened in WinDbg at an hour they would rather forget.
“What is the difference between a struct and a class in C#?”
The definition“When did you last choose a struct deliberately, and what did you measure afterwards?”
Everyone can recite stack versus heap. Almost nobody has deliberately reached for a struct, cut allocations, then gone back to check it actually helped. The checking is the signal, not the choosing.
2. Async, await and threading
Deadlocks, ConfigureAwait, cancellation, parallelism
“What does await actually do?”
“Describe a deadlock you have seen in async code. What caused it?”
The classic .Result on an async call, and an application that simply stops. Forever. No exception, no clue. Anyone who has debugged one explains why ConfigureAwait(false) mattered in library code instead of reciting it as a commandment they read once.
“How do you handle cancellation in a long-running operation?”
The judgment“What happens to work already in flight when the token fires?”
Passing the token around is the easy half. It is plumbing. The real question is what happens to the half-finished work: rolled back, committed, or quietly orphaned in a table nobody looks at. That answer separates people who designed the flow from people who wired it.
3. Memory, GC and performance
Generational GC, large object heap, allocation pressure, profiling
“How does garbage collection work in .NET?”
The definition“What did you change to reduce allocation pressure, and how did you know it worked?”
Generations and the large object heap are textbook, and the textbook is free. Pooling buffers, reaching for Span<T>, killing an allocation in a hot path and watching gen 2 collections actually drop — that is experience, and it arrives with a number attached.
“How would you approach a performance problem in production?”
The experience — most rejections happen here“What was the baseline before you started, and how was it captured?”
Every single candidate says “measure first.” Roughly none can produce the measurement. A percentage with no baseline behind it is the most common unforced error at senior level, and it stings precisely because the work was usually real.
4. EF Core and data access
Change tracking, N+1, transactions, isolation levels
“What is the N+1 problem, and how do you avoid it?”
The definition“How did you find the one in your own codebase?”
Everyone says Include. The follow-up asks whether you have ever read the generated SQL, turned on sensitive data logging in a mild panic, or watched a query counter climb past four hundred on one page load. Spotting an N+1 in the wild is a different skill from defining one.
“When would you use AsNoTracking?”
“What broke when you added it somewhere it did not belong?”
Everyone knows it makes reads faster. Fewer have shipped it somewhere it did not belong and then spent an afternoon wondering why their updates were vanishing into the void without so much as an exception.
“Explain isolation levels and when you would change the default.”
The judgment“Which anomaly were you actually trying to prevent?”
Naming read committed and serializable is recall. Naming the specific phantom read that forced someone to change it at 11pm on a release night is experience.
5. ASP.NET Core and API design
Middleware order, DI lifetimes, versioning, error handling
“How does dependency injection work in ASP.NET Core?”
The definition“Why scoped and not singleton, here?”
Everyone knows the three lifetimes. The lesson that sticks is injecting a scoped DbContext into a singleton and meeting your first captive dependency under real load, where it presents as impossible data corruption rather than anything as helpful as an error. People who have hit it describe the symptom before the theory.
“What is the order of middleware execution, and why does it matter?”
The definition“What went wrong when the order was different?”
Authentication after authorization. Exception handling registered too late to catch anything interesting. CORS in the wrong spot, producing an error message that helpfully explains nothing. Each has its own flavor of bug, and naming one beats reciting the pipeline in order.
“How do you version a public API?”
The ownership“How long did you support the old version, and who decided when to retire it?”
URL versus header versioning is a preference, and everyone has one. Retiring a version is a commitment, usually involving at least one team who swore blind they had migrated and had not.
6. Architecture and design
Service boundaries, CQRS, event sourcing, coupling
“How did you decide the service boundaries?”
The judgment — the strongest question at architect level“What operational evidence showed the boundary was right?”
Here is the thing everyone knows and nobody says out loud: most service boundaries follow the org chart, not the domain. Admitting that is a far stronger answer than a tidy Conway-free fairytale nobody believes. The evidence that a boundary was right — deploy independence, blast radius, change frequency — is what separates architecture from decoration.
“When would you use CQRS?”
The judgment“What broke first after you introduced it?”
Usually eventual consistency escaping into the UI, where a user updates something and it is simply not there yet. Or a projection rebuild that was going to take twenty minutes and took six hours. The pattern is cheap to describe and expensive to live with.
7. Distributed systems
Idempotency, distributed locks, retries, consistency
“What is a distributed lock, and what are the risks?”
The experience“What happens if the holder pauses for a GC and the lock expires mid-operation?”
Nearly everyone defines the lock correctly. Far fewer have thought about what happens when the holder stops for a GC pause, wakes up perfectly confident, and carries on holding a lock that expired two seconds ago while somebody else took it. This one reliably separates people who read about distributed systems from people who have been paged by one.
“How do you make an operation idempotent?”
The judgment“Where did the idempotency key live, and what expired it?”
The concept takes ten seconds to explain. Where the key lives, how long you keep it, and who deletes it are the questions that only turn up after the feature has been running a month and the table has nine million rows.
8. Legacy migration
WCF, WebForms, AppDomains, MSMQ, .NET Framework to .NET 8
“You migrated from .NET Framework to .NET 8. What had no clean port?”
The ownership“What did you do instead, and how long did it run that way?”
Every migration of size leaves something behind. WCF duplex callbacks have no successor. AppDomain unloading does not map cleanly onto AssemblyLoadContext, where collectible unloading is best effort and a stray reference pins the context. MSMQ has a closest relative in Azure Service Bus, but the local transactional guarantee does not survive the move — you replace the queue and inherit idempotency.
“What did you not migrate, and why?”
The ownership“What would it take to finish it now?”
A resume implying the migration finished cleanly invites this immediately, and there is no defensive answer available. Only an honest one. Which is exactly why it gets asked.
How to prepare for the second question
Lists like this one close the first gap. Annoyingly, the second gap does not close by reading anything — including this.
It closes by going back through work you already did and digging up the parts nobody wrote down. For each significant project on your resume, three things are worth recovering before somebody asks:
The mechanism. Not the outcome, the thing underneath it. What were those four hours actually made of?
The decision. What you picked, what you rejected, and why. Include the one you got wrong — that is the one they remember.
The exclusion. What you left behind, and what finishing it would cost today.
Most senior candidates can produce the first. Rounds are decided on the second and third. Which is roughly the same gap described in why good senior .NET engineers keep getting rejected.