Operation canceled: Microsoft Graph .NET SDK CancellationToken propagation
0 reputation · 02 Sept 2023, 08:19 UTC
0 reputation · 02 Sept 2023, 08:19 UTC
When utilizing the Microsoft Graph .NET SDK (v5.0+), developers can pass a CancellationToken to asynchronous methods to manage request lifecycles. While the SDK is designed to throw an OperationCanceledException when a token is triggered, there is uncertainty regarding how this cancellation propagates through the underlying HttpClient and downstream Microsoft 365 services.
The default HttpClient configuration typically implements a 100-second timeout. However, when a request is handed off to backend services—such as Exchange Online or Azure AD—it is unclear if the cancellation of the client-side token effectively terminates the processing on the server side or if the backend continues to execute the operation until a timeout occurs.
This creates a gap in understanding whether client-side cancellation truly reduces backend load or simply ignores the eventual response.
CancellationToken reliably trigger an immediate abort of the HTTP request in the underlying HttpClient?33775 reputation · 02 Sept 2023, 16:31 UTC
Cancelling the token reliably aborts the in-flight HTTP request on the client — the SDK v5 (Kiota-generated) forwards your CancellationToken down to HttpClient.SendAsync, and you get an OperationCanceledException promptly. What it does not do is signal Exchange Online, Entra ID, or any other Microsoft 365 workload to stop work already dispatched server-side. There is no documented mechanism for that, so treat client-side cancellation as a way to free client resources and stop waiting — not as a backend load-reduction tool.
HttpClient tears down the connection (TCP/TLS close, or an HTTP/2 stream reset).OperationCanceledException (or its subclass TaskCanceledException).Two practical consequences follow. First, do not assume cancelling rolls anything back: a non-idempotent POST or PATCH may already have taken effect server-side. Second, if you genuinely need to stop server-side work, use the operation-specific API where one exists — for example deleting a long-running operation resource or cancelling an async job through its dedicated endpoint — rather than the token.
The default HttpClient timeout (~100 seconds) also surfaces as TaskCanceledException, which looks identical to caller-initiated cancellation. Check the token to tell them apart:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
try
{
var users = await graphClient.Users.GetAsync(cancellationToken: cts.Token);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
// Your token fired — client-side abort.
}
catch (OperationCanceledException)
{
// Token was NOT cancelled — likely the HttpClient timeout.
}If cancellation seems not to work at all, look for custom HttpClient handlers, retry middleware, or buffered response reads that delay observing the token until the next await point.
$top or unfiltered search), cancel after ~1 second, and confirm the exception arrives in ~1 second with IsCancellationRequested == true — not at the ~100-second timeout mark.Backend propagation is not contractually documented by Microsoft and can vary per workload (Exchange, SharePoint, Entra) and change over time — the statements above describe well-established client behavior plus a likely explanation for the server side, not a guarantee. This guidance also assumes SDK v5 (Kiota); the v4 request pipeline differs, so don't apply it across major versions. For anything load-critical, confirm current semantics against the SDK and Kiota repositories before relying on them.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.