
Most .NET interviews fail on the same handful of topics: value vs reference types, how async/await actually schedules work, what LINQ does under the hood, and how ASP.NET Core's middleware pipeline gets wired up. If you can speak to those clearly — with one real example each — you're already ahead of the median candidate. This guide walks through the questions that come up most often, what a strong answer sounds like, and where junior and senior interviews diverge.
Quick map of what's ahead:
- C# fundamentals — value vs reference types, boxing, equality, generics, delegates, garbage collection
- Async and concurrency —
Task,async/await, deadlocks, cancellation - LINQ — deferred execution,
IEnumerablevsIQueryable, common pitfalls - ASP.NET Core — middleware pipeline, dependency injection, configuration, minimal APIs
- Entity Framework Core — tracking, lazy loading, migrations, the N+1 trap
- System design — designing a REST API, caching, background jobs, scaling stateful services
- Behavioral — the questions every team asks and what they're actually probing for
- Senior vs junior split — where the bar moves and how to prepare for each
C# fundamentals: the questions that filter everyone
C#) is the language layer the rest of .NET sits on, so this is where interviews start. Expect a mix of definitional questions ("what is X?") and applied ones ("here's code — what does it print?").
Value types vs reference types
This is the single most common opening question. The short answer:
- Value types (
int,bool,struct,enum,DateTime) live on the stack or inline in their container. Assignment copies the value. Twointvariables with the same number are independent. - Reference types (
class,string,object, arrays, delegates) live on the heap. The variable holds a reference. Assignment copies the reference, so two variables can point at the same instance.
The follow-up is usually about boxing: assigning a value type to an object (or any reference) wraps it on the heap, which costs an allocation. Generics avoid this — List<int> doesn't box; ArrayList does. Microsoft's value types reference is the canonical source if you want to ground your answer in the docs.
A common gotcha: string is a reference type but behaves like a value type for equality (== compares contents) and is immutable. Mention both — interviewers notice when candidates get it right without prompting.
Equality: `==` vs `.Equals()` vs `ReferenceEquals`
==— operator; can be overloaded. For most reference types it compares references;stringoverloads it to compare content..Equals()— virtual method onobject; typically compares content if the type overrides it.ReferenceEquals(a, b)— always compares references, ignores any overload.
If you override Equals, override GetHashCode too — otherwise you'll break Dictionary and HashSet lookups. Senior interviews probe this.
Generics
Generics let you write a single type or method that works across many concrete types without boxing or casting. List<T>, Dictionary<TKey, TValue>, and Task<T> are the obvious examples. The interviewer often wants you to explain type constraints (where T : class, where T : new(), where T : IComparable<T>) and covariance/contravariance (IEnumerable<out T>, Action<in T>). The official generics guide covers the constraint syntax if you need a refresher.
A concrete answer beats a definitional one:
> "Generics give me a Repository<T> that works for User, Order, or Invoice without three near-identical classes. They also avoid boxing — List<int> stores int values directly, while the old ArrayList would box every one to object."
Delegates, `Action`, `Func`, events
A delegate is a type-safe function pointer. Action<T> is a delegate returning void; Func<T, TResult> returns a value. Events are a wrapper around delegates that restricts how subscribers can mutate the underlying list (you can += but not invoke from outside).
Junior interviews stop here. Senior interviews ask why you'd use an event over a plain `Func` — the answer is encapsulation and the multicast invocation pattern, plus integration with the EventHandler<TArgs> convention the BCL uses everywhere.
Garbage collection
.NET uses a generational, tracing garbage collector. Three generations: Gen 0 (short-lived), Gen 1 (survivors of Gen 0 collection), Gen 2 (long-lived). Large objects (>85KB by default) go to the Large Object Heap. The collector runs on its own schedule; you don't call GC.Collect() in production code.
What interviewers really want to hear:
- When does GC run? When an allocation can't be satisfied within a generation's budget.
- What about `IDisposable`? It's for unmanaged resources (file handles, sockets, DB connections) — GC won't release those. Use
usingor implement the dispose pattern. - Finalizers? Avoid them unless you wrap an unmanaged handle directly. They run on a separate thread, delay collection by a full generation, and can resurrect objects.
The full mental model lives in Microsoft's garbage collection docs — worth one read before any senior interview.
Async, `await`, and the deadlock trap
Async questions split interviews cleanly: junior candidates explain what await does, senior candidates explain what it *doesn't* do.
What `async`/`await` actually does
async marks a method as a state machine. await on a Task suspends the method, returns control to the caller, and resumes when the task completes — typically on the captured synchronization context.
Three things to be ready to say:
- `async` does not start a new thread. It uses the I/O completion port for I/O-bound work. No thread is blocked while a network call is pending.
- `await` captures `SynchronizationContext` by default. In UI apps (WPF, WinForms) or old ASP.NET (not Core), this is what causes the classic deadlock when you call
.Resultor.Wait()on an async method from the UI thread. - `ConfigureAwait(false)` opts out of that capture. In library code, use it everywhere. In ASP.NET Core, it doesn't matter because there's no
SynchronizationContext.
Microsoft's async programming overview is the canonical reference and worth a skim before any senior round.
Common code-reading question
public async Task<int> GetCountAsync() {
var data = await _client.GetAsync("/api/items");
return data.Count;
}
// In a controller:
public IActionResult Index() {
var count = GetCountAsync().Result; // What's wrong?
}The answer: in classic ASP.NET this deadlocks because the request thread is captured and .Result blocks it forever. In ASP.NET Core it doesn't deadlock but still wastes a thread. The fix is await GetCountAsync() and an async Task<IActionResult> action.
Cancellation
Every public async API should accept a CancellationToken and pass it down. HttpClient, DbContext, file I/O — all of them accept tokens. Interviewers love to ask: "How would you cancel a long-running search when the user navigates away?" Answer: a linked CancellationTokenSource, passed into the work, with the controller token from HttpContext.RequestAborted.
`Task.Run` vs `async`
Task.Run schedules CPU-bound work on a thread pool thread. async/await doesn't. The rule of thumb:
- I/O-bound (HTTP, DB, disk) →
async/await, noTask.Run. - CPU-bound (image processing, heavy parsing) →
Task.Runwithawait.
A senior candidate adds: "Don't wrap every method in Task.Run to make it async. That just moves the blocking call to a thread pool thread — you've turned an I/O wait into a thread you can't reuse."
LINQ: deferred execution and the IQueryable wall
LINQ (Language Integrated Query) is a unified query syntax across collections, XML, and databases. Interview questions cluster around three areas.
Deferred execution
A LINQ query doesn't run when you write it — it runs when you enumerate it. .Where(...) returns an IEnumerable<T> that holds the query expression; .ToList(), .ToArray(), .First(), or a foreach loop forces evaluation.
The classic trap:
var users = GetUsers(); // IEnumerable<User>
var actives = users.Where(u => u.IsActive);
foreach (var u in actives) { ... } // Query runs here
foreach (var u in actives) { ... } // Query runs AGAINIf GetUsers() hits the database, you've made two round trips. The fix: .ToList() once and reuse the list.
`IEnumerable<T>` vs `IQueryable<T>`
IEnumerable<T>— query runs in memory, in the .NET process..Where(predicate)calls your lambda for each item.IQueryable<T>— query is translated to an expression tree and executed by a provider (EF Core, MongoDB driver, etc.)..Where(predicate)becomes part of a SQLWHEREclause.
The transition between them is where bugs hide. The moment you call .ToList(), .AsEnumerable(), or pass an IQueryable to a method that takes IEnumerable, the rest of the query runs in memory — which can mean pulling the whole table.
Senior interviewers test this with: "What does this query do?"
var users = db.Users
.AsEnumerable()
.Where(u => u.IsActive)
.ToList();Answer: SELECT all users from the database, then filter in memory. The AsEnumerable() is the bug.
The full LINQ guide covers query syntax, method syntax, and the standard query operators if you want to top up your vocabulary before the interview.
Common operators worth knowing cold
| Operator | What it does |
|---|---|
Select | Project each item to a new shape |
Where | Filter by predicate |
GroupBy | Group items by key |
Join / GroupJoin | Combine two sequences |
Aggregate | Reduce to a single value |
Any / All | Existence checks |
First / FirstOrDefault | Get one (throws vs returns default) |
Single / SingleOrDefault | Get exactly one (throws if 0 or 2+) |
Know when First throws (empty source) and when Single throws (empty *or* multiple). Senior candidates volunteer that SingleOrDefault is the right call when you mean "this should be unique by contract — fail if it isn't."
ASP.NET Core: middleware, DI, configuration
ASP.NET Core is the most-asked-about framework. Three areas dominate.
The middleware pipeline
ASP.NET Core processes each request through a pipeline of middleware components. Each component sees the request, optionally short-circuits or modifies it, then calls next to pass it down. The response unwinds back up.
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();Order matters. Authentication must run before authorization. Routing must run before endpoint mapping. The middleware docs cover the convention and how to write your own. A common interview question is "write a middleware that logs request duration" — the answer is a class with an InvokeAsync(HttpContext context, RequestDelegate next) method that wraps a Stopwatch around await next(context).
Dependency injection
ASP.NET Core has dependency injection built in. Three lifetimes:
- Transient — new instance every time. Use for stateless services.
- Scoped — one instance per HTTP request. The default for most services.
DbContextis scoped. - Singleton — one instance for the app's lifetime. Use only for stateless or thread-safe state.
The single most common bug to know: capturing a scoped service inside a singleton. It silently keeps that scoped instance alive forever, which often means a DbContext that holds onto a connection or tracked entities across requests. The fix is to inject IServiceProvider or IServiceScopeFactory and create a scope each time the singleton needs the scoped dependency.
Configuration
IConfiguration reads from a chain of providers — appsettings.json, appsettings.{Environment}.json, environment variables, command-line args, user secrets, Azure Key Vault — in a defined order, with later providers overriding earlier ones. Strongly-typed binding via services.Configure<MyOptions>(Configuration.GetSection("My")) is the modern pattern; injecting IConfiguration directly is fine for one-offs but not for anything you'd test.
Minimal APIs vs Controllers
Minimal APIs (introduced in .NET 6) let you define endpoints inline:
app.MapGet("/users/{id}", async (int id, IUserService svc) =>
await svc.GetAsync(id));Use them for small services or for endpoints that don't need filters, model binding extensions, or shared base classes. Controllers stay the right call for larger apps with conventions, filters, and complex action results. Interviewers often ask "when would you pick one over the other" — there's no single right answer, but be ready to defend your choice.
Entity Framework Core: tracking, lazy loading, N+1
EF Core is the dominant ORM in .NET. Most production bugs come from misunderstanding three things.
Change tracking
By default, DbContext tracks every entity it loads. When you call SaveChanges, it computes the diff and generates SQL. This is convenient but expensive when you're just reading.
.AsNoTracking() skips tracking — use it for read-only queries. For large result sets, this is a meaningful speedup.
Lazy vs eager vs explicit loading
- Eager —
.Include(u => u.Orders). One query, joined. - Explicit — load later with
context.Entry(user).Collection(u => u.Orders).Load(). - Lazy — auto-load on property access (requires proxies, off by default in EF Core). Convenient but causes the N+1 problem.
The N+1 problem: querying a list of N users, then accessing user.Orders in a loop, fires 1 + N queries. The fix is .Include() upfront. Senior interviews expect you to spot this in code.
Migrations
dotnet ef migrations add InitialCreate generates a migration from the current model diff. dotnet ef database update applies it. In CI, you generate a SQL script (dotnet ef migrations script) and apply that — never run Update-Database against production from a developer machine.
A trap question: "What happens if two developers add migrations on different branches and both merge?" Answer: EF detects the model snapshot mismatch and refuses. The fix is to delete one migration, re-run add, and rebase the model snapshot.
Common interview code question
var users = await db.Users
.Where(u => u.IsActive)
.ToListAsync();
foreach (var u in users) {
Console.WriteLine($"{u.Name}: {u.Orders.Count}"); // Lazy load here?
}In EF Core without lazy-loading proxies, u.Orders is null and the loop NREs. With proxies enabled, it fires N queries. The right answer is .Include(u => u.Orders) on the original query — or a projection that selects only what you need.
System design questions for .NET roles
Beyond senior, expect a 45-minute design problem. Common prompts:
- "Design a URL shortener." Probe: hash strategy (random vs counter+base62), storage (SQL vs Redis vs key-value), caching, rate limiting, analytics.
- "Design a REST API for a job board." Probe: resource modeling, pagination, authentication (JWT? cookies?), versioning, idempotency for
POSTretries. - "Design a background job system." Probe: queue choice (Azure Service Bus, RabbitMQ, in-process channel), at-least-once vs exactly-once delivery, retries with exponential backoff, dead-letter queue, observability.
- "How would you cache the homepage?" Probe: in-memory vs distributed (Redis), cache-aside vs read-through, invalidation strategy, stampede protection.
The structure interviewers want:
- Clarify requirements. Reads vs writes? Latency target? Scale (RPS, data volume)? Consistency model?
- Sketch the components. Boxes and arrows. API, DB, cache, queue.
- Pick technologies and justify. "Postgres for transactional data, Redis for sessions, Azure Service Bus for jobs — because [reason tied to requirements]."
- Walk a request through the system. Show you've thought about failure modes.
- Identify the scaling bottleneck before they ask.
A senior candidate also volunteers: monitoring (OpenTelemetry + Application Insights or Grafana), deployment topology (containers in AKS or App Service), and what would change at 10x scale.
Behavioral questions: what they're actually asking
Behavioral rounds aren't filler. They're the round most engineers underprepare for, which is why they're often where strong candidates lose. A few high-frequency ones and what's underneath each:
- "Tell me about a time you disagreed with a teammate." Probe: do you escalate productively or sulk?
- "Walk me through a project you're proud of." Probe: can you talk about technical decisions, not just outcomes?
- "Tell me about a bug you struggled to find." Probe: do you have a debugging methodology or do you guess?
- "Why are you leaving your current role?" Probe: are you running *to* something or *from* something?
The STAR format (Situation, Task, Action, Result) works fine — keep stories under two minutes and lead with the result. If you want sample answers and frameworks for the most common ones, our guide on how to answer "What are your weaknesses" and the breakdown of strong "tell me about yourself" responses cover the templates that actually land.
Junior vs senior: where the bar moves
The same questions appear at every level. What changes is the depth of follow-up.
| Topic | Junior bar | Senior bar |
|---|---|---|
| Value vs reference types | Define them, give examples | Explain boxing cost, when string behaves like value |
async/await | Use it correctly in a controller | Explain SynchronizationContext, deadlocks, ConfigureAwait |
| LINQ | Write Where/Select/GroupBy | Spot the AsEnumerable performance trap, deferred execution |
| Dependency injection | Inject services into a controller | Explain the captive-dependency bug, when to use IServiceScopeFactory |
| EF Core | Use DbContext, write a query | Detect N+1, choose AsNoTracking, design migrations for prod |
| System design | Not usually asked | Full whiteboard design with tradeoffs |
Junior candidates often fail by going too deep — long lectures on IL and how await lowers to a state machine. Senior candidates fail by going too shallow — answering "we used DI" without explaining how they'd untangle a captive dependency in a 200k-line codebase.
Prep for your level. If you're applying to a senior role, write down one production war story per major topic — that's the unlock for the follow-ups.
Past the technical loop, the real bottleneck
Most .NET interviews aren't lost on the technical questions — they're lost waiting for a recruiter to reply, or never reaching the team in the first place. Technical chops get you through the algorithm round, but reaching the hiring manager before you apply is what short-circuits the funnel.
Resumes and interview answers carry you to the door. What gets you through it is a 15-minute conversation with the person hiring. Articuler is built to find that person across 980M+ professional profiles and help you reach them with a personalized note that gets ~8x the reply rate of generic cold emails — plus a Playbook on the specific interviewer so you walk in prepared for *that* conversation, not a generic one.
FAQ
How long should I spend preparing for a .NET interview?
For a senior role at a mid-sized company, two weeks of focused prep is usually enough if you're already working in .NET daily. Spend one week on the language and runtime (C#, async, LINQ, GC), one week on the framework you'll be using (ASP.NET Core, EF Core), and roll one mock system-design session into each weekend. If you've been out of .NET for a year or more, double that.
Do I need to know LeetCode-style algorithms for .NET roles?
Most product engineering roles in .NET shops weight system design and applied framework knowledge more than algorithm trivia. Some FAANG-adjacent companies still run a LeetCode round even for .NET roles, so check the company's interview guide on Glassdoor or ask the recruiter directly. If you're applying broadly, a baseline of about 30-50 medium-difficulty problems is the safe floor.
What's the difference between .NET Framework and .NET (Core)?
.NET Framework is the original Windows-only runtime that shipped from 2002. .NET (formerly .NET Core) is the modern cross-platform, open-source runtime that has been the recommended target since 2019. Greenfield work is on .NET 8 or 9. Legacy enterprise apps may still be on .NET Framework 4.8. If a job listing mentions ".NET" without a version, ask which one — the codebase is meaningfully different.
Should I memorize design patterns for .NET interviews?
Know the patterns the framework forces you to use — Singleton, Factory, Observer (events), Strategy (delegates), Repository, Unit of Work, Mediator. Don't memorize all 23 GoF patterns. Interviewers want to hear you describe a real situation where the pattern earned its complexity, not recite the textbook definition.
How do I prepare for the system-design round if I've never done one?
Pick three classic problems — URL shortener, chat app, news feed — and write the design out by hand. Then watch one or two whiteboard videos to see the format. The structure (clarify → sketch → tech choices → request walkthrough → scale-up) is more important than knowing every technology. If you can walk an interviewer through that loop calmly, you'll pass.