Back to Blog

84 .NET Interview Questions With Answers — Junior to Architect (2026 Edition)

Roundexa Team 2 Sep 2026
84 .NET Interview Questions With Answers — Junior to Architect (2026 Edition)

Most .NET question lists still teach you to define dependency injection. No interviewer above the fresher level asks that any more. They describe a broken production system and watch how you reason.

This list is built the way real loops run: every question is either a symptom you have to diagnose or a judgment call you have to defend, each carries a level tag, and each has a short answer containing the specific detail panels listen for. There is also a hard deadline attached to this topic right now — .NET 8 and .NET 9 both reach end of support on 10 November 2026, and .NET 10 is the current LTS through November 2028. Half the migration questions in current loops exist because of that date.

How to Use This List

Level tags are the point. [Junior] means you should answer without hesitation. [Senior] means you should answer and then name the trade-off. [Architect] means there is no single correct answer and the reasoning is the answer.

Work through it once and mark every question you could not answer out loud in sixty seconds. That marked set is your actual gap — far more useful than a completion percentage.

One warning: do not memorize these answers. They are deliberately short so you can expand them from your own project experience. An answer delivered in someone else's words is obvious within two follow-up questions.

C# Language and CLR Fundamentals

Q1 · Junior

Value type vs reference type — what actually differs?

Not "stack vs heap" — a struct field inside a class lives on the heap alongside its owner. The real difference is copy semantics: assigning a struct copies the whole value, assigning a class copies a reference. A struct larger than roughly 16 bytes, or one that gets boxed repeatedly, costs more than the class it replaced.

Q2 · Junior

What is boxing, and where does it silently cost you?

Wrapping a value type in a heap object so it can be treated as object. Each box is a Gen 0 allocation. The classic sources are non-generic collections, string.Format with value types on a hot path, and struct-to-interface conversions inside loops.

Q3 · Junior

Why is string concatenation in a loop a problem, and what replaces it?

Strings are immutable, so each += allocates a new string and copies the old one — O(n²) work and O(n²) garbage. Use StringBuilder for loops, string.Join when the shape is known, and string.Create when you are optimizing a genuinely hot path.

Q4 · Senior

What is the difference between IEnumerable<T> and IQueryable<T>?

IEnumerable executes in memory using delegates. IQueryable builds an expression tree that a provider translates into SQL. This is the single most expensive mistake in EF Core code: assigning a DbSet to an IEnumerable variable before calling Where() pulls the entire table into memory and filters in C#. Identical output, catastrophically different behaviour.

Q5 · Senior

What is deferred execution, and how does multiple enumeration burn you?

A LINQ query does not run until it is enumerated. Enumerating the same query twice runs it twice — two database round trips, and potentially two different results. Materialize once with ToList() at the boundary where you leave the query world.

Q6 · Senior

When do you implement IDisposable, and when IAsyncDisposable?

When your type owns something scarce that the GC does not manage: file handles, sockets, connections, timers. Use IAsyncDisposable when cleanup itself needs to await — flushing a stream, closing a connection gracefully. Finalizers are a last-resort safety net and actively hurt: an object with a finalizer survives one extra GC generation.

Q7 · Junior

When is a record the right choice over a class?

When identity is the data — DTOs, API contracts, messages, configuration snapshots — because you get value equality and non-destructive with copies for free. It is the wrong choice for an EF Core entity, which is tracked by key identity and mutated in place.

Q8 · Senior

What do nullable reference types actually guarantee?

Nothing at runtime. It is compile-time flow analysis only. JSON deserialization, EF Core materialization and reflection all happily produce null in a field declared non-nullable. Validate at the boundaries; the annotations are documentation the compiler helps you keep honest, not a runtime contract.

Q9 · Senior

When do Span<T> and pooled buffers genuinely help?

Parsing, slicing and buffer manipulation on a hot path, where they remove allocations entirely. The constraint that surprises people: Span<T> is a ref struct, so it cannot live on the heap and therefore cannot cross an await or sit in a lambda — use Memory<T> there. Outside a measured hot path this is premature and makes code harder to read.

Async, Await and the Thread Pool

Q10 · Junior

What does await actually do to your method?

The compiler rewrites the method into a state machine. At the first incomplete await, the method returns to its caller and the thread is released. When the awaited operation completes, the continuation is scheduled on a thread pool thread. No thread sits and waits during I/O — that is the entire point.

Q11 · Senior

Why is async void dangerous?

There is no Task to await, so the caller cannot know when it finished and cannot catch its exceptions — an unhandled exception in an async void method goes straight to the process-level handler and can crash the app. The only legitimate use is an event handler.

Q12 · Senior

What breaks when you call .Result or .Wait() on an async method?

In ASP.NET Core the classic deadlock is gone because there is no synchronization context, but the more common failure remains: you block a thread pool thread for the entire duration of the I/O. A few of these under load produce thread pool starvation. GetAwaiter().GetResult() is not a safer version — it only changes how the exception is wrapped.

Q13 · Senior

Is ConfigureAwait(false) still necessary?

In ASP.NET Core application code, no — there is no context to capture, so it is a no-op. It still matters in library code you ship to unknown consumers, because a WPF, WinForms or legacy ASP.NET host does have a context, and capturing it can deadlock their app.

Q14 · Senior

Task vs ValueTask — when is the second worth it?

When the result is usually already available, so the Task allocation is pure waste — a cache lookup that hits 95% of the time. The rules are strict: await it exactly once, never block on it, never store it or await it twice. If you cannot guarantee that, use Task.

Q15 · Architect

Your API times out under load while CPU sits at 15%. What is happening?

Thread pool starvation. Requests are queued waiting for a thread while the existing threads are blocked on synchronous calls inside async code. Confirm it before acting: dotnet-counters on the threadpool-queue-length and threadpool-thread-count counters — a growing queue with idle CPU is the signature.

Q16 · Architect

You have confirmed starvation. How do you find the exact blocking call in production?

Capture a dump (dotnet-dump collect) and inspect thread stacks, or run dotnet-stack report. You are looking for many threads parked on the same frame — typically .Result, .Wait(), Thread.Sleep, a synchronous file or database API, or a lock. Static analysis with an analyzer catches most of these before deployment.

Q17 · Senior

Where must a CancellationToken flow, and what happens when it does not?

From HttpContext.RequestAborted all the way down to the database and HTTP calls. Without it, a client who gave up thirty seconds ago is still holding a database connection and burning CPU on a query nobody will read. Under load this alone can be the difference between degraded and down.

Q18 · Senior

You need to call a downstream API five hundred times. How do you not take it down?

Bound the concurrency. Parallel.ForEachAsync with MaxDegreeOfParallelism, or a SemaphoreSlim gate around the calls. Task.WhenAll over five hundred tasks is an unintentional denial-of-service against your own dependency, and the retries that follow will make it worse.

Runtime, Deployment and Hosting

Q19 · Junior

.NET Framework, .NET Core, modern .NET — what is the practical difference today?

.NET Framework is Windows-only and effectively frozen at 4.8. .NET Core was the cross-platform rewrite. From .NET 5 onward they are one platform on an annual November cadence, alternating LTS and STS. Concretely right now: .NET 10 is the current LTS with support to November 2028, while .NET 8 and .NET 9 both go out of support in November 2026.

Q20 · Senior

What happens to your code between compilation and execution?

C# compiles to IL in an assembly. At runtime the JIT compiles IL to machine code per method, on first call. Tiered compilation compiles quickly first and re-optimizes hot methods later, which is why the first requests after a deploy are slower. Native AOT moves compilation to build time and eliminates the JIT entirely.

Q21 · Senior

Framework-dependent or self-contained deployment — how do you choose?

Framework-dependent for a machine or base image you control, where a runtime patch should not require rebuilding every service. Self-contained when you need version isolation or cannot guarantee the runtime is present. Self-contained means every security patch to the runtime is now your rebuild-and-redeploy problem.

Q22 · Architect

What do trimming and Native AOT actually break?

Anything resolved by reflection at runtime, because the trimmer cannot see it and removes it. In practice: reflection-based JSON serialization, some DI registration patterns, EF Core, and libraries that generate types dynamically. The fix is source generators — a JsonSerializerContext for serialization — plus honest testing of the trimmed artifact, not the debug build.

Q23 · Junior

Kestrel is running, but IIS or Nginx sits in front. Which one serves your app?

Kestrel always serves the app. The reverse proxy terminates TLS, handles connection management and forwards the request. Kestrel is the web server; the proxy is a front door.

Q24 · Senior

Behind a proxy your app sees the wrong client IP and scheme, and redirects loop. What is missing?

ForwardedHeaders middleware, registered first in the pipeline. The subtle part: by default it only trusts loopback, so in a container or Kubernetes deployment you must configure KnownProxies or KnownNetworks — or clear them deliberately — otherwise the headers are silently ignored and everything looks the same as before.

The Middleware Pipeline

Q25 · Junior

How does a request travel through the pipeline?

Each component receives the context, may act, then calls next() to pass control inward. When the innermost component completes, control unwinds back out through every await next() in reverse order. That is why code after await next() runs on the way out — and why it runs after the response may already be underway.

Q26 · Senior

Give the correct middleware order for a typical API, and justify it.

Exception handling → HSTS and HTTPS redirection → static files → routing → CORS → authentication → authorization → rate limiting → endpoints. Exception handling is first because it can only catch what happens inside it. CORS sits before authentication because a preflight OPTIONS request carries no credentials and would otherwise be rejected before the CORS headers are ever written. Authorization must follow authentication because it needs an identity to evaluate.

Q27 · Senior

Use, Run and Map — what is the difference?

Use runs and may call the next component. Run is terminal and never calls next. Map branches the pipeline on a path prefix. Anything registered after a terminal component is dead code that will never execute — and it fails silently, which is what makes it a good interview question.

Q28 · Senior

Your middleware sets a status code after await next() and throws "response has already started". Why?

Once any bytes are written, headers and status are committed and immutable. Anything downstream that started writing has already committed them. Restructure so the decision happens before calling next, or buffer the response through HttpResponse.OnStarting and modify it in that callback instead.

Q29 · Senior

Your middleware needs a scoped service. Why does constructor injection create a bug?

Middleware is instantiated once, at startup — it is effectively a singleton. Injecting a scoped service into its constructor captures the first request's instance forever, which is a captive dependency and a data-leak risk across users. Inject it as a parameter of InvokeAsync instead, where the container resolves it per request.

Dependency Injection Internals

Q30 · Junior

Explain Transient, Scoped and Singleton in terms of state, not instance counts.

Transient: no shared state, safe by default, cheapest to reason about. Scoped: state shared within one request, so it must never be touched by another request or a background thread. Singleton: state shared by the whole application across all concurrent requests, so every mutable field must be thread-safe. The lifetime you choose is a thread-safety commitment, not a performance setting.

Q31 · Senior

What is a captive dependency, and why does it pass locally and fail in production?

A longer-lived service holding a shorter-lived one — a singleton capturing a scoped DbContext. Locally, with one user and sequential requests, the captured instance behaves fine. In production, concurrent requests share it, and DbContext is not thread-safe: you get corrupted change tracking, "a second operation was started on this context" errors, and occasionally another user's data. Enable scope validation in all environments, not just Development.

Q32 · Senior

You register three implementations of one interface. What does resolving it give you?

The last one registered. To get all three, inject IEnumerable<IYourInterface>. To choose a specific one by name, use keyed services (AddKeyedScoped, .NET 8+). Prefer separate interfaces when the implementations are not genuinely interchangeable — keyed services make a design smell easy to keep.

Q33 · Senior

Who disposes the services the container creates?

The container disposes what it created: scoped instances at the end of the request, singletons at application shutdown. The case that surprises people is that it does not dispose an instance you registered yourself with AddSingleton(new MyThing()) — you handed it an object, not a recipe, so ownership stayed with you.

Q34 · Senior

Your BackgroundService needs a DbContext. Why is constructor injection a trap?

A hosted service is a singleton that lives for the whole application, so it would hold one DbContext for days — accumulating tracked entities, holding a connection, and eventually failing. Inject IServiceScopeFactory and create a fresh scope inside each iteration of the work loop.

Configuration and Options

Q35 · Junior

Two providers set the same key. Which wins?

The last one registered. The default order is appsettings.json, then appsettings.{Environment}.json, then user secrets in Development, then environment variables, then command-line arguments — so a command-line argument overrides everything.

Q36 · Senior

IOptions, IOptionsSnapshot, IOptionsMonitor — which belongs in a background service?

IOptionsMonitor. IOptions is a singleton computed once and never reloads. IOptionsSnapshot is scoped, so it cannot be injected into a singleton at all. IOptionsMonitor is a singleton that supports reload and change notification — the only one that works for a long-running hosted service.

Q37 · Senior

How do you make invalid configuration fail the deployment rather than a customer request at 3am?

.Bind(...).ValidateDataAnnotations().ValidateOnStart(). This moves the failure to startup, where your rolling deployment halts and the previous version keeps serving. Without it, a missing connection string is discovered by whichever unlucky user first hits the code path that needs it.

APIs, Routing and Serialization

Q38 · Senior

Minimal APIs or controllers for a large team?

Controllers give convention, discoverability and a familiar filter model, which matters when twenty people touch the codebase. Minimal APIs are leaner, start faster and are AOT-friendly. The pragmatic answer for a large team: minimal APIs are fine if you enforce a grouping and registration convention — without one, endpoint definitions scatter across the solution and nobody can find anything in a year.

Q39 · Senior

How does model binding decide where a parameter comes from, and why can only one bind from the body?

By convention: route values, then query string, then header, then body — overridable with [FromQuery], [FromBody] and friends. Only one parameter can bind from the body because the request body is a forward-only stream that can be read once. Two body parameters would require the framework to buffer and guess how to split it.

Q40 · Senior

What is the Minimal API equivalent of an action filter?

An endpoint filter. Unlike middleware, it runs after routing and model binding, so it can see the resolved endpoint metadata and the actual bound argument values — which is exactly what you need for validation, auditing or per-endpoint authorization logic that middleware cannot express.

Q41 · Senior

How would you version a public API, and what do you version?

URL segment versioning (/v1/orders) is the least surprising for consumers and easiest to route and cache. Version the contract, not the code — additive changes should not create a new version at all. The real discipline is a deprecation policy with dates, because the cost of versioning is carrying old versions, not creating new ones.

Q42 · Senior

System.Text.Json or Newtonsoft.Json, and why do source generators matter?

System.Text.Json is the default and is significantly faster, but it is strict where Newtonsoft was forgiving — case sensitivity, comments, trailing commas and some polymorphic scenarios. Use a source-generated JsonSerializerContext when you need trimming or Native AOT to work, and to remove reflection cost from startup. Reach for Newtonsoft only for a specific feature you cannot replicate.

EF Core and Data Access

Q43 · Junior

How does change tracking work, and what happens on SaveChanges?

On materialization, EF stores a snapshot of each entity. SaveChanges compares current values against the snapshot, generates INSERT/UPDATE/DELETE for what differs, and executes them inside a single transaction. Nothing is sent to the database before that call.

Q44 · Senior

When do you turn tracking off, and what do you lose?

AsNoTracking for read-only queries — list screens, reports, API GETs. You save the snapshot memory and the comparison work on large result sets. You lose the ability to modify and save those entities, and you lose identity resolution, so the same row appearing twice in a join produces two separate objects.

Q45 · Senior

How does the N+1 problem arise, and how do the loading strategies differ?

One query returns N parents, then accessing a navigation property on each fires one query per parent. Eager loading (Include) fetches upfront in one round trip. Lazy loading causes N+1 by design and is why it is off by default. Explicit loading is manual and deliberate. Detect it by logging queries in development and counting them, not by reading the code.

Q46 · Senior

Include fixed my N+1 but the query got slower. Why?

Cartesian explosion. Multiple collection Includes produce a cross-product, so the parent's columns are repeated once per combination of child rows and you transfer far more data than you need. AsSplitQuery() issues one query per collection instead — more round trips, dramatically less data. It is a trade-off, not a fix, and the right choice depends on the collection sizes.

Q47 · Senior

How do you run migrations safely across environments, and what would you never do in production?

Never call Database.Migrate() on application startup. With multiple replicas they race, and a failed migration takes down the deployment mid-flight with no rollback path. Generate an idempotent SQL script, review it in the pull request like code, and apply it as a separate deployment step. Also: schema changes and code deploys should be independently reversible, which means expand-then-contract, never rename in one step.

Q48 · Senior

Two users update the same record. What does optimistic concurrency actually detect?

A row version or concurrency token column is included in the UPDATE's WHERE clause. If another transaction changed the row first, zero rows match, and EF throws DbUpdateConcurrencyException. It detects that the row changed since you read it — not what changed, and not whether the two changes actually conflict semantically. Resolving that is your business logic's job.

Q49 · Senior

How would you insert several hundred thousand rows efficiently?

Not with a loop of SaveChanges — that is one round trip per row plus a change tracker that grows unbounded. Use SqlBulkCopy or an equivalent bulk API, in batches, with tracking disabled. If it must stay in EF, batch it and use a new context per batch so the tracker stays small.

Q50 · Architect

A query looks fine in C# but generates terrible SQL. How do you find that out?

Log the generated SQL (LogTo with EnableSensitiveDataLogging in development only), then take that SQL to the database and read the actual execution plan. You are looking for three things: client-side evaluation, an implicit type conversion that killed an index, and a missing index. The C# is rarely the problem; the translation and the plan are.

Memory, GC and Diagnostics

Q51 · Architect

Your API's memory climbs all day and drops on restart. Is it a leak?

Not necessarily — the GC does not return memory to the OS eagerly, and a large cache is not a leak. Prove it: force a full collection and see whether managed heap size drops. If it does not, take two dotnet-gcdump snapshots an hour apart and diff them. You are looking for a type whose count grows monotonically, then for what roots it — usually a static collection, an unremoved event handler, or a cache with no eviction policy.

Q52 · Senior

Server GC vs Workstation GC, and why might your setting be ignored?

Server GC uses per-core heaps and threads for throughput; Workstation GC optimizes for latency on a single heap. ASP.NET Core defaults to Server GC. In a container with a low CPU limit, the runtime adapts heap count to the available cores — so the aggressive multi-heap behaviour you configured may not be what you actually get. Always check the container's CPU limit before blaming the setting.

Q53 · Senior

What is DATAS, and why does it matter to teams upgrading right now?

Dynamic Adaptation To Application Sizes — the GC adjusts heap count and size to the application's actual working set instead of assuming it should use everything available. It became the default for Server GC in .NET 9, which means teams moving from .NET 8 can see materially different memory behaviour with no code change. It usually reduces memory; on throughput-sensitive workloads it can cost a little, and it can be disabled.

Q54 · Senior

What lands on the Large Object Heap, and what is the fix that is not a GC setting?

Allocations of 85,000 bytes or more — big arrays, large strings, buffers. The LOH is collected only with Gen 2 and is not compacted by default, so it fragments and holds memory. The fix is to stop allocating there: ArrayPool<T>, streaming instead of buffering whole payloads, and paginating queries. Enabling LOH compaction treats the symptom at the cost of long pauses.

Q55 · Architect

Gen 0 collections are cheap, so why is your p99 spiking?

Individually cheap, collectively expensive. A high allocation rate means thousands of Gen 0 collections per minute, each a small pause, and objects surviving them get promoted — turning a Gen 0 problem into a Gen 2 problem. Check allocation rate and the Gen 2 collection count, not just the pause duration. The fix is allocating less on the hot path, not tuning the GC.

Q56 · Architect

Your process holds far more memory than the heap snapshot accounts for. Where is the rest?

Native memory: thread stacks (about 1 MB each — a starved thread pool is expensive twice over), unmanaged libraries, pinned buffers fragmenting the heap, the JIT's own allocations, and memory the GC has released internally but not returned to the OS. dotnet-counters gives you the split between managed heap and working set; a native leak needs different tools than a managed one.

Caching, HTTP and Resilience

Q57 · Senior

When is "just add a cache" the wrong answer?

When the underlying query is slow because of a missing index — you have now hidden a five-second query behind a cache that will eventually miss, usually under load. Also when the data must be correct rather than fast, when the hit rate will be low, or when invalidation is genuinely hard. A cache is a consistency trade you are choosing to make; if you cannot say what staleness is acceptable, you are not ready to add it.

Q58 · Senior

In-memory, distributed, or hybrid caching — which first?

In-memory is fastest and simplest but is per-instance, so with five replicas you have five caches and five invalidation problems. Distributed (Redis) is shared and survives restarts, at the cost of a network hop and serialization. HybridCache (.NET 9+) layers both with stampede protection built in, and is the sensible default for new work rather than hand-rolling the two-tier pattern.

Q59 · Architect

A hot key expires under load and every request hits the database at once. How do you prevent it?

Cache stampede. Single-flight the refresh so only one caller recomputes while the rest wait or serve stale, add jitter to expiry so keys do not expire in lockstep, and refresh ahead of expiry rather than on it. HybridCache does the first of these for you; before it existed, this was a SemaphoreSlim keyed per cache entry.

Q60 · Senior

Why is new HttpClient() per call a problem, and what does the factory fix?

Each instance creates its own handler and its own connection pool, and disposed sockets sit in TIME_WAIT — under load you exhaust ports. The naive fix, a static HttpClient, swaps that for a subtler bug: the handler caches DNS resolution forever, so a failover the DNS record already reflects never reaches your app. IHttpClientFactory pools handlers and rotates them on a lifetime, solving both.

Q61 · Senior

Where can retries make an outage worse?

When a dependency is degraded rather than down, retries multiply the load that is already overwhelming it — a retry storm turns a slow service into a dead one. You need a circuit breaker to stop calling, exponential backoff with jitter so clients do not synchronize, a retry budget rather than a fixed count, and the discipline of never retrying a non-idempotent operation without an idempotency key.

Security

Q62 · Junior

Authentication and authorization — how does the pipeline handle each?

Authentication establishes who the caller is and populates HttpContext.User. Authorization decides whether that identity may perform this action. UseAuthentication must run before UseAuthorization, because the second one has nothing to evaluate without the first.

Q63 · Senior

What does JWT validation actually check?

The signature against the issuer's published signing keys, plus issuer, audience and lifetime. What it does not check is revocation — a valid token stays valid until it expires, which is exactly why access token lifetimes should be short and why "log out" cannot invalidate a bearer token on its own. If you need immediate revocation, you need a reference token or a revocation list.

Q64 · Senior

Role-based or policy-based authorization?

Roles answer "which group is this user in" and stop working the moment the rule involves data — "can edit this order if they own it and it is not yet shipped". Policies with requirements and handlers express that, are testable in isolation, and keep the rule in one place instead of scattered across controllers.

Q65 · Junior

Why does a CORS preflight fail when the middleware order is wrong?

The browser sends an unauthenticated OPTIONS request before the real one. If UseCors sits after authentication or authorization, that preflight is rejected before the CORS headers are written, so the browser blocks the actual request — and the error the developer sees mentions CORS, not authentication, which sends most people looking in the wrong place.

Q66 · Architect

What is the Data Protection API, and why does it need explicit configuration in containers?

It encrypts and signs framework-issued payloads: antiforgery tokens, auth cookies, temp data. By default the keys are written to the local filesystem or user profile — which in a container is ephemeral, and across a load balancer is per-instance. The result is intermittent "invalid antiforgery token" and users logged out after a restart. Persist keys to shared storage (Blob, Redis) and protect them with a KMS key.

Q67 · Senior

How would you protect an API from abuse?

Built-in rate limiting (.NET 7+) gives you fixed window, sliding window, token bucket and concurrency limiters with a queue and a rejection response. Partition by API key or user, not just IP, because IP partitioning punishes everyone behind a corporate NAT. Rate limiting is a fairness mechanism at the edge — it is not a substitute for authorization or input validation.

Distributed Systems and Messaging

Q68 · Architect

You need to save to the database and publish an event. Why can you not just do both?

Because there is no atomic transaction across a database and a message broker. Commit-then-publish loses the event if the process dies in between; publish-then-commit emits an event for a transaction that rolled back. The transactional outbox pattern fixes it: write the event into an outbox table inside the same transaction, and have a separate relay read that table and publish. The database transaction becomes the single source of truth.

Q69 · Architect

Your queue guarantees at-least-once delivery. What must every consumer do?

Be idempotent. Duplicates are not an edge case — a retry after a slow acknowledgment produces them routinely. Practically: carry a message ID, record processed IDs with a unique constraint, and make the handler's effect the same on the second execution. "Exactly-once delivery" does not exist across a network; exactly-once processing is what idempotency buys you.

Q70 · Architect

How do you handle a business transaction spanning three services?

A saga: a sequence of local transactions, each with a compensating action, coordinated either by orchestration (one service drives the steps) or choreography (services react to each other's events). Orchestration is easier to debug and to reason about failure in; choreography couples less but the flow exists only in everyone's heads unless you trace it. For most teams, orchestration first.

Q71 · Architect

Users see stale data immediately after saving because reads go to a lagging replica. How do you fix it?

Read-your-own-writes. Options in order of preference: return the resulting state from the write itself so the client does not re-read; route that user's reads to the primary for a short window after their write; or hold a version token and wait for the replica to catch up. Increasing replica hardware is not a fix — replication lag is a property of the design, not the machine.

Q72 · Architect

When is moving off a relational database actually justified?

When the access pattern genuinely does not fit: write volumes a single primary cannot absorb, schemaless documents with no cross-entity queries, or time-series and search workloads with purpose-built engines. What you give up is transactions, joins, ad-hoc queries and thirty years of tooling — usually far more than teams estimate. Most 'we need NoSQL' conversations end when someone reads the execution plan.

Observability in Production

Q73 · Architect

Which four numbers go on the dashboard, and why is latency a percentile?

Request rate, error rate, latency percentile and saturation (thread pool queue length, CPU, connection pool usage). Latency must be p95/p99 because an average hides the tail entirely — an endpoint averaging 80ms can still have one in fifty users waiting six seconds, and those are the users who complain.

Q74 · Senior

You have 40 GB of logs a day and still cannot explain why one request was slow. What is wrong?

The logs are text, not data. Without a correlation ID on every line and structured properties you can filter on, volume works against you. Log structured events with a trace ID, log at boundaries with duration, and delete the "entering method" noise — it is what made the volume unusable in the first place.

Q75 · Senior

How would you add distributed tracing, and what do you correlate on?

OpenTelemetry with W3C Trace Context propagated through HTTP headers and message properties. You correlate on trace ID, and every log line carries it, so a slow request opens as a single timeline across all services. The step people skip: propagating the context through the message broker, which is where the trace silently breaks.

Q76 · Senior

Liveness or readiness — what belongs in each?

Liveness answers 'is this process broken beyond recovery, should you restart me' and must depend on nothing external. Readiness answers 'can I serve traffic right now' and may check dependencies. Putting a database check in the liveness probe is a classic outage amplifier: one database blip restarts every instance simultaneously, and now you have two problems.

Q77 · Architect

p50 is 40ms, p99 is 6 seconds. Where do you look first?

Not at the code path — it is the same code for both. Look for something that affects a subset of requests: GC pauses, thread pool queuing, connection pool exhaustion, a cold cache, one bad instance in the pool, or a specific tenant with far more data. Break the percentile down by instance and by endpoint before touching anything; the tail usually collapses onto one dimension.

Q78 · Architect

Production is slow, you cannot attach a debugger and cannot deploy. What order do you use?

Cheapest and least invasive first: dotnet-counters to see which resource is stressed, then dotnet-trace or dotnet-stack to see what threads are doing, then dotnet-dump or dotnet-gcdump when you need the full picture. A dump is a pause and a large artifact — it is the last step, not the first. On Azure, the diagnostic profiler collects most of this without any tooling installed.

Architecture, Migration and Judgment

Q79 · Architect

You inherit a codebase with three competing patterns. What do you do in your first month?

Nothing structural. Ship small changes to learn the system, find out why each pattern exists — usually a person or a deadline, not a decision — and write down the target pattern. Then apply it only to new code and to files you are already touching for other reasons. A month-one refactor of a system you do not understand, with no tests, is how new architects lose credibility permanently.

Q80 · Architect

Your team wants to adopt a new technology. How do you decide?

Ask what specific problem it solves that you currently have, what the exit cost is if it fails, and who supports it at 3am. Then run it on one non-critical service for a quarter. The decisive question is rarely technical: can you hire for it, and can the person who did not pick it debug it?

Q81 · Architect

How do you decide which technical debt to pay down?

Score it by how often it is touched and what it costs when touched. Debt in code nobody opens is free — leave it. Debt in the file every feature must modify compounds weekly and is worth a sprint. The category to pay regardless of frequency is anything that makes failure hard to diagnose, because that debt is charged during an incident when you can least afford it.

Q82 · Architect

The architecture is wrong and a rewrite is off the table. What is your play?

Strangler fig. Put a routing layer in front, build new capability in the new shape, migrate one bounded slice at a time — starting with a slice that is valuable enough to fund the work and isolated enough to finish. Every step ships and is reversible. The failure mode is starting three slices at once and living permanently in both worlds.

Q83 · Architect

You have a .NET Framework monolith and a mandate to modernise. What is the plan?

Inventory dependencies first and find the genuine blockers, then move to .NET Standard-compatible libraries, then extract the seams that can move independently, then migrate the host. Sequence by risk, not by which module is most annoying. Give the deadline teeth: .NET 8 and .NET 9 both leave support in November 2026, so anything already on modern .NET needs a version plan too, not just the legacy code.

Q84 · Architect

What exists in .NET Framework with no modern equivalent, and what does that do to your estimate?

Web Forms, WCF server-side hosting (CoreWCF covers part of it), Windows Workflow Foundation, AppDomains, .NET Remoting, and some System.Drawing scenarios on Linux. These are not ports — they are rewrites of that component, and they are where migration estimates go wrong by a factor of three. Find them in week one, before anyone commits to a date.

How to Prepare by Experience Level

  • 0–2 years: every [Junior] question, plus sections 2 and 3 in full. If you can explain what await does to a method and why IEnumerable and IQueryable differ, you are ahead of most candidates at this level.
  • 2–5 years: all [Junior] and [Senior] questions. The highest-yield sections are DI internals, EF Core and async — those three produce the majority of real production incidents, which is exactly why they produce the majority of interview questions.
  • 5+ years / lead: the [Architect] set, answered with a story. "We hit thread pool starvation on a payments API; CPU was flat at 12% while p99 went to nine seconds" beats a textbook definition every single time. Prepare three such stories: one performance incident, one bad architectural decision you owned, one migration.

FAQs

How many .NET interview questions should I prepare?

Around 80-100 understood properly beats 300 memorized. Understood means you can answer the follow-up — "and what would you do if that did not work?" — which is where memorized answers collapse.

Which .NET version should I target in 2026?

.NET 10, the current LTS, supported to November 2028. .NET 8 and .NET 9 both reach end of support in November 2026, so if your current project is on either, expect to be asked about your upgrade plan.

Do I need Azure knowledge for a .NET role?

For most enterprise roles, yes at a working level: App Service or AKS, Key Vault, Service Bus, Application Insights. You are not expected to be a cloud architect, but "we deploy it somehow" is a visible gap.

Are Minimal APIs replacing controllers?

No. They are the default for new small services and the AOT-friendly option, but controllers remain common in large codebases and are not deprecated. Expect to be asked to compare them rather than to pick a winner.

What do interviewers actually reject candidates for at senior level?

Not missing facts. Confidently wrong answers with no hedging, an inability to say "I do not know, here is how I would find out", and no evidence of ever having debugged something in production.

Final Thoughts

The pattern across all 84 of these is the same: interviewers above the fresher level are not testing recall, they are testing whether you have actually operated the thing you claim to know. Build that evidence with real projects and timed mock interviews at Roundexa.com.

Ready to Practice?

Take a free AI mock interview on Roundexa and get instant, actionable feedback before the real one.

Practice on Roundexa