Skip to content

Latest commit

 

History

History
47 lines (30 loc) · 2.04 KB

File metadata and controls

47 lines (30 loc) · 2.04 KB

HCR063

Avoid sync-over-async around outbound HTTP.

Why

Blocking on outbound HTTP tasks with .Result, .Wait(), or .GetAwaiter().GetResult() can starve thread pools, deadlock synchronization contexts, and hide cancellation or timeout behavior. Prefer async all the way through the call path.

Bad

var response = client.GetAsync("https://example.com").Result;
client.SendAsync(request, cancellationToken).Wait();
var body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

Better

var response = await client.GetAsync("https://example.com", cancellationToken);
var body = await response.Content.ReadAsStringAsync(cancellationToken);

Current Detection

The implementation reports .Result, .Wait(), and .GetAwaiter().GetResult() when they are applied directly to visible HttpClient async calls such as GetAsync(...), SendAsync(...), or PostAsync(...), or to visible local task variables initialized from those calls before reassignment. It also reports the same blocking shapes for common HttpContent async read methods such as ReadAsStringAsync().

Receivers are validated with Roslyn type information when available, with syntactic fallback for unresolved snippets that visibly declare an HttpClient receiver. Awaited calls are skipped, arbitrary non-HTTP tasks are skipped, locals that are reassigned before blocking are skipped, and resolved custom HttpClient lookalikes are skipped.

Suppression

Suppress only at deliberate synchronous boundaries where the caller cannot be made async and the blocking behavior has been reviewed for thread-pool, cancellation, and timeout impact.

References