Interview blog

25 Dotnet Interview Questions That Cover Core Concepts and Production Scenarios

Written February 10, 2026Updated May 20, 202622 min read
How Can You Master .Net Interview Questions

Use these dotnet interview questions to cover CLR, C#, ASP.NET Core, async/await, EF Core, and production debugging scenarios.

Most candidates who struggle with .NET interviews aren't missing knowledge — they're missing the connection between what they know and how it behaves when something goes wrong in production. The dotnet interview questions that trip people up aren't the definitions. They're the follow-ups: "Okay, but what happens to that object when the GC runs?" or "How would that middleware behave if the auth check throws?" This guide moves from fundamentals into Web API mechanics, production trade-offs, and debugging scenarios in a deliberate sequence, so you can answer the second question as confidently as the first.

These questions were pulled from real interview loops, code reviews, and the follow-up patterns that kept showing up across junior-to-mid .NET roles. The goal isn't to hand you 25 memorized answers. It's to build a path where each topic prepares you for the next one.

Core .NET interview questions you need to answer fast

The first five minutes of a .NET interview almost always covers the platform itself. Get these wrong and you've already created doubt. Get them right and you've bought yourself credibility for the harder questions that follow.

What is .NET, and how do you explain it without sounding like you memorized a docs page?

The clean version: .NET is a developer platform — a runtime, a set of libraries, and a compiler toolchain — that lets you write applications in multiple languages (C#, F#, VB) and run them on Windows, Linux, or macOS. The runtime is what actually executes your code. The language is how you express it. The libraries are what you call to do anything useful.

The part that separates a practiced answer from a docs recitation is knowing where the boundaries are. .NET isn't a language. C# is a language that compiles to Intermediate Language (CIL), which the .NET runtime then executes. When an interviewer asks this, they're checking whether you understand that the platform, the runtime, and the language are three different things that happen to work together.

How do CLR, CIL, JIT, assemblies, and GC fit together when a program runs?

When you compile a C# project, the compiler produces an assembly — a `.dll` or `.exe` — containing CIL (Common Intermediate Language), not native machine code. The Common Language Runtime (CLR) is the execution engine that takes that assembly and runs it. The Just-In-Time (JIT) compiler, which is part of the CLR, converts CIL to native machine code at runtime, typically the first time a method is called. After that, the native version is cached.

The Garbage Collector (GC) runs inside the CLR and manages heap memory. It tracks object references, decides when objects are unreachable, and reclaims memory in generational sweeps. The follow-up pressure point here is almost always: "What triggers a GC collection, and what does it cost?" The honest answer is that Gen 0 collections are cheap and frequent, Gen 2 collections are expensive and block threads, and objects that survive long enough to reach Gen 2 are the ones that can silently hurt throughput. Microsoft's .NET runtime documentation covers the generational model in detail.

What is the difference between managed and unmanaged code, and why do interviewers keep asking it?

Managed code runs inside the CLR and gets memory management, type safety, and exception handling for free. Unmanaged code — native DLLs, COM objects, OS APIs — runs outside the CLR and owns its own memory lifecycle.

The reason this question keeps showing up is that the boundary matters the moment you use P/Invoke or COM interop. Say you're calling a native image-processing library from a .NET API. If that library allocates memory and your wrapper doesn't call the right cleanup function, you get a memory leak the GC can't see or fix. The `SafeHandle` and `IDisposable` patterns exist precisely to manage this boundary. The interviewer is checking whether you understand that managed doesn't mean indestructible — it means the CLR is responsible, and when you step outside, you take that responsibility back.

How do value types and reference types behave differently in memory?

The textbook answer — value types go on the stack, reference types go on the heap — is mostly true but incomplete, and interviewers know it. The real trap is boxing: when you assign an `int` to an `object` or pass it to a method expecting `object`, the runtime wraps the value in a heap-allocated object. That allocation is invisible in source code but real in memory. In a tight loop or a hot path, unintentional boxing is a measurable performance problem.

The other trap is copying. Value types are copied on assignment. Reference types copy the reference, not the object. This means two variables can point to the same object, and mutations through either variable affect both. Nullable value types (`int?`) add a third wrinkle: they're structs with a boolean flag, not references, so they don't cause null reference exceptions the same way a nullable reference type does.

What should you say when asked about LINQ and collection behavior?

LINQ over in-memory collections like `List<T>` executes immediately when you call `ToList()` or iterate. LINQ over an `IQueryable<T>` provider like EF Core translates the expression tree into SQL and executes against the database when you enumerate. The dangerous version is calling `.Count()` twice on an `IQueryable` — that's two round trips. Or calling `.ToList()` early and then filtering in memory on a million rows.

The concrete example that surprises people: `var query = dbContext.Orders.Where(o => o.Status == "Pending")` does nothing until you iterate it. If you pass that `IQueryable` to three different methods that each enumerate it, you've made three database calls. The fix is materializing with `.ToList()` once, then filtering in memory — but only after you've applied all the server-side predicates you need.

C# interview questions that expose whether you actually write code

When should you choose an interface over an abstract class?

Abstract classes make sense when you have shared implementation — a base `PaymentProcessor` that handles retry logic, logging, and error wrapping, with subclasses that override just the provider-specific call. The abstract class carries the behavior; the subclasses carry the variation.

Interfaces win when you need flexibility across unrelated types, when you're designing for testability, or when a class needs to satisfy multiple contracts. A `ReportGenerator` that also implements `IExportable` and `ISchedulable` can't inherit from two abstract classes, but it can implement both interfaces. The interview is really testing whether you understand that interfaces model capability and abstract classes model identity. When you need to mock something in a unit test, you almost always want an interface — the mock doesn't share behavior, it substitutes it.

How do you explain encapsulation, inheritance, and polymorphism without drifting into schoolbook language?

Use a payments example. Encapsulation: a `PaymentService` exposes `ProcessPayment(order)` and hides how it talks to the gateway, validates the card, and handles retries. The caller doesn't need to know. Inheritance: a `StripePaymentService` extends a base class that handles the shared retry and logging logic. Polymorphism: a method that accepts a `IPaymentProvider` can work with Stripe, PayPal, or a test double without changing the calling code.

The code review version of this question is when a junior developer creates a deep inheritance hierarchy to share one method, and the senior engineer points out that composition would have been simpler and easier to test. That's the real conversation the interviewer is trying to get to.

What is the difference between IEnumerable, IQueryable, and List in practice?

`List<T>` is a concrete in-memory collection. `IEnumerable<T>` is a forward-only cursor over any sequence — it could be a list, a file, a generator, anything. `IQueryable<T>` adds expression tree support, which is how EF Core translates LINQ into SQL.

The concrete example: `IEnumerable<Order> orders = dbContext.Orders.Where(o => o.Total > 100)` will pull every order from the database and filter in memory. `IQueryable<Order> orders = dbContext.Orders.Where(o => o.Total > 100)` pushes the filter to SQL. Same syntax, completely different execution location. Returning `IEnumerable` from a repository method that wraps an `IQueryable` is one of the most common performance bugs in EF Core codebases. Microsoft's LINQ documentation covers the distinction between deferred and immediate execution.

What do generics buy you in a real codebase?

Type safety without duplication. A `Result<T>` wrapper that carries either a value or an error works for any return type without casting or boxing. A `Repository<T>` that handles common CRUD patterns once, then gets specialized per entity. The interviewer's follow-up is almost always about constraints: `where T : class`, `where T : IEntity`, `where T : new()`. Constraints let you call methods on `T` that the compiler can verify exist — without them, you can only treat `T` as `object`.

How do you talk about records, pattern matching, and nullable reference types without sounding trendy?

Records are for immutable data with value-based equality. A `Money` record with `Amount` and `Currency` is safer than a mutable class because you can't accidentally mutate it after construction, and two records with the same values are equal by default. Pattern matching makes branching on type or shape explicit and exhaustive — the compiler warns you when you've missed a case in a switch expression. Nullable reference types, enabled at the project level, turn null into an explicit contract: `string?` means nullable by design, `string` means the compiler expects you to guarantee it's not null. The bug it prevents is the null reference exception you'd only find at runtime without it.

ASP.NET Core interview questions that test whether you understand the request pipeline

How does dependency injection actually work in ASP.NET Core?

The built-in DI container resolves services registered in `Program.cs` or `Startup.cs`. The three lifetimes are transient (new instance every time), scoped (one instance per HTTP request), and singleton (one instance for the application's lifetime). The lifetime mismatch that breaks things in practice: injecting a scoped service into a singleton. The singleton lives forever; the scoped service was meant to live for one request. The singleton holds a reference to a stale, potentially disposed scoped instance. ASP.NET Core will throw an `InvalidOperationException` in development mode if it detects this, but not always in production. ASP.NET Core's DI documentation covers lifetime validation in detail.

What is middleware, and how do requests move through the pipeline?

Middleware is a chain of components that each receive the request, do something, and either pass it to the next component or short-circuit. The order you register them in `Program.cs` is the order they execute. This matters enormously: if you put exception handling after authentication, an auth failure won't be caught by the exception handler. If you put logging after routing, you lose the route data in the log entry.

A concrete case: a request comes in, hits the exception handling middleware first (which wraps the rest in a try/catch), then authentication, then authorization, then the endpoint. If authentication fails, the pipeline short-circuits and returns 401 — the endpoint never runs. If the endpoint throws, the exception handling middleware catches it and returns a structured error response.

How do routing and model binding work together?

Routing matches the incoming URL to an endpoint. Model binding populates the endpoint's parameters from the route, query string, headers, or request body. The confusing bugs happen at the seam between them: a route template that expects `{id:int}` gets a string, and the request returns 404 instead of 400 because the route didn't match at all. Or a complex object in the request body doesn't bind because the `Content-Type` header is wrong, and the parameter arrives as null with no error.

The practical answer is knowing which binding source is active by default for which parameter type, and when to use `[FromBody]`, `[FromRoute]`, or `[FromQuery]` explicitly to remove ambiguity.

What is the point of an endpoint filter or minimal API in modern .NET?

Minimal APIs reduce the ceremony of defining HTTP endpoints — no controller class, no action method, just a route and a handler. They're fast to write and fast to execute. Endpoint filters are the minimal API equivalent of action filters: they run before or after the handler and are useful for validation, logging, or authorization logic that applies to a group of endpoints.

Where they stop being the right tool: large APIs with complex routing, versioning, content negotiation, or heavy use of action filters are still better served by controllers. Minimal APIs are a simplification, not a replacement for every scenario.

How do you answer questions about forwarded headers and reverse proxies?

When ASP.NET Core runs behind Nginx, a load balancer, or a cloud gateway, the original client IP, scheme (HTTP vs HTTPS), and host are stripped and replaced with the proxy's details. The `ForwardedHeaders` middleware reads `X-Forwarded-For`, `X-Forwarded-Proto`, and `X-Forwarded-Host` headers and restores the original values. Without it, `HttpContext.Connection.RemoteIpAddress` returns the proxy's IP, `Request.Scheme` returns `http` even when the client connected over HTTPS, and redirect URLs break because the host is wrong. This is a production bug that's invisible in local development and obvious the moment you deploy.

Async, cancellation, and throughput questions interviewers love to spring on you

What is async/await actually doing?

It's a compiler transformation that turns a method into a state machine. When you `await` something, the method suspends, returns control to the caller, and resumes when the awaited task completes — on a thread pool thread, not necessarily the original thread. The key clarification interviewers want: async doesn't create threads. It frees threads while waiting for I/O. On a CPU-bound workload, `async` adds overhead without benefit.

When does async improve throughput, and when is it just cosmetic?

For an API endpoint that calls a database or an external service, async frees the thread pool thread while the I/O is in flight. Under load, this means more concurrent requests with fewer threads. For an endpoint that does pure in-memory computation, async does nothing for throughput and adds a small allocation overhead from the state machine. The honest answer in an interview: async is almost always right for web API handlers because most of them wait on I/O. It's wrong as a reflex for CPU-bound work, where `Task.Run` and proper parallelism are the actual tools. Microsoft's async guidance covers the I/O-bound versus CPU-bound distinction explicitly.

Why does CancellationToken matter in web APIs?

When a client aborts a request — closes the browser tab, hits the back button, or times out — ASP.NET Core signals cancellation through the `HttpContext.RequestAborted` token. If your handler ignores it, the work continues: the database query runs, the external API call completes, the response is assembled, and then it's discarded because the client is gone. At scale, that wasted work piles up. Passing `CancellationToken` through to `dbContext.SaveChangesAsync(ct)`, `HttpClient.GetAsync(url, ct)`, and your own async loops means the work stops when the client stops caring.

What is the difference between Task, ValueTask, and just returning a result?

`Task<T>` always allocates a heap object. For methods that are frequently called and often complete synchronously — like a cache lookup that hits 95% of the time — that allocation is measurable overhead. `ValueTask<T>` avoids the allocation in the synchronous completion case. The honest answer: don't reach for `ValueTask` by default. It's an optimization for specific high-frequency paths, and misusing it (by awaiting the same `ValueTask` twice, or storing it) introduces bugs. Most application code should use `Task<T>` and profile before optimizing.

EF Core, caching, and auth questions that reveal production judgment

How do you explain EF Core change tracking, migrations, and query translation?

Change tracking means EF Core watches every entity it loads and compares its state at `SaveChanges` time to generate the right SQL. It's powerful and invisible — until you load 10,000 entities in a loop and wonder why memory usage spikes. `AsNoTracking()` disables it for read-only queries and is one of the most impactful single-line optimizations in EF Core. Migrations are versioned schema changes that EF Core generates from model diffs. Query translation is the process of converting LINQ expressions into SQL — and when it can't translate something, it either throws or silently pulls everything into memory and filters there.

What happens when two users update the same row at the same time?

This is an optimistic concurrency scenario. EF Core supports it through a concurrency token — typically a `RowVersion` column. When user A and user B both load an order, then both try to save changes, EF Core includes the original `RowVersion` in the `WHERE` clause of the `UPDATE`. One of them will match zero rows and throw a `DbUpdateConcurrencyException`. The application catches it and decides: retry, show a conflict message, or merge. The interview answer isn't just naming the exception — it's explaining what the application does next in a checkout or order-edit scenario.

When should you use caching, and when does it just hide a problem?

Caching is the right tool for data that's expensive to compute, changes infrequently, and can tolerate some staleness — reference data, configuration, aggregated reports. It's the wrong tool when it's masking a slow query that should be indexed, or when invalidation logic is complex enough that the cache is frequently stale and requires manual clearing. The real interview signal is whether you can articulate the staleness window, the invalidation strategy, and the fallback when the cache is cold — not just that you've used `IMemoryCache` or Redis.

How do you talk about authentication and authorization in an interview without mixing them up?

Authentication answers "who are you?" — verifying identity through a token, cookie, or credential. Authorization answers "what are you allowed to do?" — checking whether the verified identity has permission for the specific action. The concrete API scenario: a valid JWT token authenticates the user successfully, but the endpoint requires the `admin` role claim. The user is authenticated but not authorized — 401 is wrong here, 403 is right. Getting that status code wrong in an interview signals that the distinction isn't clear.

How do you decide what HTTP status code to return in a broken API flow?

Validation failure on the request body: 400 Bad Request, with a body that explains what was wrong. Missing authentication: 401 Unauthorized. Valid authentication but missing permission: 403 Forbidden. Resource not found: 404 Not Found. Optimistic concurrency conflict: 409 Conflict. Unhandled server error: 500 Internal Server Error. The interviewer wants to see that you reason from the scenario to the code, not that you've memorized a list. The question underneath is: does your API tell the client something useful, or does it just say 500 for everything?

Modern .NET interview questions that separate current candidates from stale ones

Why do minimal APIs matter, and when do they not?

Minimal APIs remove the controller-action ceremony for simple HTTP services. A microservice that exposes three endpoints doesn't need a full MVC controller stack. The setup is smaller, the routing is explicit, and the performance is measurable — minimal APIs have less overhead per request than the full MVC pipeline. Where they stop making sense: large APIs with complex versioning, multiple content types, deeply nested route groups, or heavy reliance on action filter pipelines. At that scale, controllers provide structure that minimal APIs don't.

What should you say about observability and structured logging?

"Use logs" is not an answer. Useful structured logging means emitting fields that can be queried: `{"TraceId": "abc123", "UserId": "42", "OrderId": "999", "DurationMs": 145, "Outcome": "Success"}`. Correlation IDs let you trace a single request across multiple services. The difference between debugging and measuring is the difference between a log message that tells you something went wrong and a log entry that tells you how often, for which users, and how long it took. Tools like Serilog or the built-in `ILogger` with structured sinks make this tractable. The interview answer should mention what you'd emit, not just that you'd log.

How do Docker and deployment questions show up in .NET interviews?

Developers should know: how to write a multi-stage Dockerfile that builds the app and produces a lean runtime image, how to pass configuration through environment variables rather than baking it into the image, which ports the app listens on, and what the difference between `ENTRYPOINT` and `CMD` is. What they don't need to own: the Kubernetes cluster configuration, the ingress controller, the CI/CD pipeline orchestration. The interview is checking whether you can ship a containerized service, not whether you're a platform engineer.

How do you explain testing strategy for .NET APIs?

Unit tests cover business logic in isolation — services, validators, domain rules — with all dependencies mocked. Integration tests cover the interaction between components: a test that spins up a real `WebApplicationFactory`, makes an HTTP call, and checks the response against a real (test) database. API tests cover the contract from the outside: does the endpoint return the right shape, the right status codes, the right headers? The interview question underneath is: how do you know the service works before it hits production? The answer is a combination of all three, weighted toward the layer where the most logic lives.

The follow-up questions that usually decide whether you get the offer

What if the interviewer asks you to go one layer deeper?

The pattern that works: pause, restate what you just said in one sentence, then add one specific detail that connects it to production behavior. "So I said GC runs generational sweeps — the part that matters in practice is that Gen 2 collections are stop-the-world events, and objects that survive long enough to get there are usually the ones you didn't realize were holding references." That's not a longer definition. It's the same answer with one real consequence attached.

What if they challenge your trade-off choice?

Don't retreat. Defend the decision with the conditions that made it right, then acknowledge where the trade-off bites. "I'd choose async here because this endpoint waits on a database call and I want the thread pool thread free while that's in flight. The trade-off is the state machine overhead, which matters if this path is called thousands of times per second on a CPU-bound workload — but for a web API handler, the I/O wait dominates." That's a defensible answer. Changing your position because the interviewer pushed back signals that you didn't have a reason in the first place.

What if they ask you to debug a failing endpoint on the spot?

Start with the observable symptom, not the hypothesis. "The endpoint returns 400 — so either the route didn't match, the model didn't bind, or validation failed. I'd check the route template first, then look at what the model binder is receiving, then check whether a data annotation or a custom validator is rejecting the input." For a timeout: "I'd check whether the database query is missing an index, whether a downstream HTTP call has no timeout configured, and whether a `CancellationToken` is being respected so the work stops when the client gives up." Calm, sequential reasoning is the signal the interviewer wants.

What makes a good interview answer instead of a textbook answer?

A clear claim in the first sentence. Correct terminology used naturally, not performed. One concrete example from something that could plausibly happen in a real codebase. One trade-off — where the approach helps and where it costs something. One sentence that shows you've seen the problem behave in practice, not just read about it. That structure works for fundamentals, for production scenarios, and for follow-ups. It's not a script — it's a habit of thinking that sounds like someone who has actually shipped software.

How Verve AI Can Help You Prepare for Your Interview With Dotnet Interview Questions

The structural problem with .NET interview prep isn't content — there's plenty of it. The problem is that reading answers and giving answers under pressure are completely different skills. You can know exactly what a `DbUpdateConcurrencyException` is and still fumble the explanation when an interviewer asks "so what does your application actually do when that throws?" The gap closes with practice, not more reading.

Verve AI Interview Copilot is built for exactly that gap. It listens in real-time to the live conversation and responds to what you actually say — not a canned prompt. If you give a clean first answer about middleware order and the interviewer follows up with "what happens if the exception handler is registered after authentication?", Verve AI Interview Copilot surfaces the relevant context and suggests how to extend your answer, right in the moment. It stays invisible while it does this, so the conversation feels natural. The capability that changes the calculus for .NET prep specifically is that Verve AI Interview Copilot can run mock scenarios around the follow-up patterns — the ones where interviewers push past the definition into the production consequence — so you've already navigated that pressure before the real interview starts.

The goal isn't memorizing 25 answers. It's building the reflex to go one layer deeper when the thread gets pulled — and that reflex only forms through repetition under realistic conditions.

The point of working through these questions in sequence isn't to have 25 answers ready. It's to build a mental model where each concept connects to the next one — where CLR knowledge informs your async answer, where your async answer informs your API design answer, and where all of it informs how you reason through a debugging scenario you've never seen before. Interviewers keep pulling the thread because they're not checking recall. They're checking whether the knowledge is load-bearing. Use this list as a drill path, rehearse the follow-ups out loud, and practice defending the trade-off even when someone pushes back. That's what survives pressure.

KD

Kevin Durand

Career Strategist

Ace your live interviews with AI support!

Get Started For Free

Available on Mac, Windows and iPhone