A synchronous ASP.NET Core MVC action (running under the default request context in a legacy self-hosted scenario with a SynchronizationContext) calls `var data = GetDataAsync().Result;`. Inside `GetDataAsync`, an `await httpClient.GetStringAsync(url)` is used without `ConfigureAwait(false)`. The request hangs forever. What is the precise root cause?
- A. The HttpClient instance is not thread-safe and blocks its own connection pool
- B. The awaited continuation is posted back to the captured SynchronizationContext, whose only thread is already blocked on .Result waiting for that continuation ✓
- C. GetStringAsync internally uses a ThreadPool thread that is exhausted by the blocking call
- D. .Result throws an AggregateException that is silently swallowed, leaving the task incomplete
Correct answer: B. The await captures the single-threaded context; the continuation is queued to a thread that is blocked on .Result, so neither can proceed — ConfigureAwait(false) avoids capturing the context and breaks the deadlock.
Consider: `var actions = new List<Func<int>>(); for (int i = 0; i < 3; i++) actions.Add(() => i); Console.WriteLine(string.Join(",", actions.Select(a => a())));` in C# 4.0 semantics (pre-C# 5 foreach fix, classic for loop). What is printed?
- A. 0,1,2
- B. 3,3,3 ✓
- C. 0,0,0
- D. 2,2,2
Correct answer: B. A `for` loop's counter `i` is a single variable captured by reference by all closures, so after the loop each lambda reads the final value 3 — unlike `foreach`, which since C# 5 declares a fresh variable per iteration.
You register `IClock` (a Scoped service that reads a per-request tenant id) and inject it into a Singleton `CacheWarmer`. In production the warmer intermittently serves data for the wrong tenant. What is the correct explanation and fix?
- A. Scoped services are thread-unsafe by design; wrap IClock access in a lock
- B. The Singleton captured the first request's scoped IClock instance (captive dependency); inject IServiceScopeFactory and resolve IClock inside a created scope per operation ✓
- C. Scoped lifetime is invalid for interfaces; re-register IClock as Transient to get a fresh instance each call
- D. The DI container leaks the scope; call GC.Collect() after each request to release it
Correct answer: B. A Singleton resolving a Scoped dependency captures it once for the app's lifetime (the captive dependency problem); the fix is to inject IServiceScopeFactory and create a scope per unit of work.
This EF Core query loops `foreach (var o in ctx.Orders.ToList()) { total += o.Customer.Name.Length; }` with lazy loading enabled. Against 1,000 orders it issues 1,001 database round trips. Which single change eliminates the N+1 without changing tracked results?
- A. Add `.AsNoTracking()` to the Orders query
- B. Replace `.ToList()` with `.AsEnumerable()` to stream results
- C. Use `ctx.Orders.Include(o => o.Customer).ToList()` so Customer is loaded in the same query ✓
- D. Wrap the loop in a single explicit transaction with Serializable isolation
Correct answer: C. Each `o.Customer` access triggers a separate lazy-load query (the N+1); `Include` eager-loads Customer in the original query, collapsing 1,001 round trips into one.
A payment service receives the same 'charge $50' message twice due to at-least-once broker delivery. To make the handler idempotent so the customer is charged once, which design is correct and race-safe under concurrent duplicate delivery?
- A. Check `SELECT` for an existing charge with the same idempotency key, then `INSERT` if absent — in two separate statements
- B. Persist the charge with the client-supplied idempotency key under a UNIQUE constraint in the same transaction as the charge, treating a duplicate-key violation as 'already processed' ✓
- C. Add a 5-second in-memory dedup cache of recently seen message ids on each service instance
- D. Configure the broker for exactly-once delivery so the handler needs no idempotency logic
Correct answer: B. A non-atomic check-then-insert has a TOCTOU race under concurrency; a UNIQUE constraint on the idempotency key committed atomically with the charge lets the database enforce single-charge semantics, and exactly-once broker delivery is generally unattainable end-to-end.
In an ASP.NET Core pipeline, a developer writes `app.UseRouting(); app.UseEndpoints(...); app.UseAuthorization();` (authorization added AFTER endpoints). Requests to `[Authorize]` endpoints succeed even when unauthenticated. Why?
- A. UseAuthorization only works with cookie auth, not JWT bearer
- B. The authorization middleware is registered after the endpoint has already executed, so its policy check never runs for the matched endpoint ✓
- C. Endpoint routing disables all middleware ordering, so position is irrelevant
- D. UseAuthorization must be called before UseRouting to build the endpoint graph
Correct answer: B. Middleware runs in registration order; placing UseAuthorization after the endpoint execution means the terminal endpoint handles the request before the authorization check can enforce the policy.
Under sudden load, a service that does `httpClient.GetAsync(...).GetAwaiter().GetResult()` on every request sees requests time out and thread count climb, even though CPU is near-idle. What is happening?
- A. Thread pool starvation: each request blocks a pool thread on I/O, the pool grows only ~1 thread/500ms, so incoming work queues faster than threads are injected ✓
- B. The garbage collector is pausing all threads in a Gen 2 full collection under load
- C. HttpClient's connection pool is exhausted, forcing synchronous DNS lookups on each call
- D. The CLR is JIT-recompiling the hot path repeatedly, consuming threads
Correct answer: A. Sync-over-async blocks a thread pool thread for the whole I/O duration; the pool injects new threads slowly, so under load the queue outpaces thread injection — classic thread pool starvation despite idle CPU.
You have `struct Point { public int X; public void Inc() => X++; }` and store instances in a `List<Point>`. Calling `myList[0].Inc()` does not change the stored value, but calling `Inc()` on a `Point[]` element via `myArray[0].Inc()` does. Why the difference?
- A. List<T> boxes value types on insertion, so Inc mutates a boxed copy
- B. List<T>'s indexer returns a copy of the struct (a method call), while an array element access returns a direct reference to the element ✓
- C. Arrays store structs by reference while List<T> stores them by value
- D. The array version also fails; both leave the original unchanged
Correct answer: B. `List<T>`'s indexer is a property returning a by-value copy that Inc mutates and discards, whereas array indexing yields a direct addressable location so the in-place mutation sticks — a well-known mutable-struct trap.
A method returns `ValueTask<int>`. A caller writes `var vt = obj.ComputeAsync(); int a = await vt; int b = await vt;` where the implementation pools its IValueTaskSource. What is the correct assessment?
- A. Fully safe — ValueTask is just a lightweight Task and can be awaited any number of times
- B. Awaiting the same ValueTask twice is undefined behavior; the backing IValueTaskSource may be reset/reused, so the second await can throw or return a wrong/torn result ✓
- C. The second await always returns the cached result with zero cost, which is the point of ValueTask
- D. It only fails if the ValueTask wraps a Task; pooled sources are always safe to re-await
Correct answer: B. A ValueTask backed by a pooled IValueTaskSource must be consumed exactly once; the token/version can be recycled after the first await, making a second await undefined behavior.
A high-throughput producer/consumer needs bounded buffering with backpressure so fast producers block when consumers fall behind, plus native async consumption. Which primitive best fits and why over the alternatives?
- A. `ConcurrentQueue<T>` with a busy-wait polling consumer loop for lowest latency
- B. `Channel<T>` created bounded with `BoundedChannelFullMode.Wait`, exposing an async writer that yields on a full buffer and an IAsyncEnumerable reader ✓
- C. `BlockingCollection<T>`, since its async support gives non-blocking backpressure out of the box
- D. `List<T>` guarded by a single lock, resizing to absorb bursts
Correct answer: B. A bounded `Channel<T>` in Wait mode provides asynchronous, non-thread-blocking backpressure and native async reads; BlockingCollection blocks threads, ConcurrentQueue has no built-in bounding/backpressure, and a locked List is neither async nor bounded.