Files
Roger Barreto 9d8c3f8cb7 Simplify ClientHeadersScope, drop redundant using/Dispose (#5676)
Wesley pointed out (with a clean demo) that AsyncLocal<T> mutations made
inside an awaited async method do not leak back to the caller after the
method returns - the runtime restores the caller's view automatically.

ClientHeadersAgent.RunCoreAsync and RunCoreStreamingAsync are the only
callers of the scope, both are async methods awaited by their callers,
so the explicit using/Dispose pattern was doing work the runtime already
does for us.

* ClientHeadersScope collapsed to a single Current { get; set; } property
  over an AsyncLocal<IReadOnlyDictionary<string,string>?>. Drops Push,
  the Scope struct, and Dispose. XML doc explains the AsyncLocal natural-
  restoration semantics so the design intent is self-documenting.
* ClientHeadersAgent uses a direct ClientHeadersScope.Current = snapshot
  before delegating. Drops the local RunAsyncCoreAsync helper and the
  snapshot-passed-as-parameter dance.
* Test 10 renamed to ClientHeadersScope_IsAsyncLocalIsolatedAndAutoRestoresAsync;
  drops the LIFO claim, keeps the parallel-isolation assertion, and adds
  a Wesley-style 'set inside async, caller sees null on return' assertion.
* Test 12 switches from using ClientHeadersScope.Push to direct
  Current = ... with try/finally for test isolation.

Snapshot deep-copy in TrySnapshot stays - it defends against caller
mutating the source Dictionary mid-run, which is independent of the
AsyncLocal restoration mechanism.
9d8c3f8cb7 ยท 2026-05-11 13:38:14 +00:00
History
..