private void CancelCall(Status status) { // Set overall call status first. Status can be used in throw RpcException from cancellation. // If response has successfully finished then the status will come from the trailers. // If it didn't finish then complete with a status. _callTcs.TrySetResult(status); // Checking if cancellation has already happened isn't threadsafe // but there is no adverse effect other than an extra log message if (!_callCts.IsCancellationRequested) { GrpcCallLog.CanceledCall(Logger); // Cancel in-progress HttpClient.SendAsync and Stream.ReadAsync tasks. // Cancel will send RST_STREAM if HttpClient.SendAsync isn't complete. // Cancellation will also cause reader/writer to throw if used afterwards. _callCts.Cancel(); // Cancellation token won't send RST_STREAM if HttpClient.SendAsync is complete. // Dispose HttpResponseMessage to send RST_STREAM to server for in-progress calls. HttpResponse?.Dispose(); // Canceling call will cancel pending writes to the stream ClientStreamWriter?.WriteStreamTcs.TrySetCanceled(); ClientStreamWriter?.CompleteTcs.TrySetCanceled(); ClientStreamReader?.HttpResponseTcs.TrySetCanceled(); } }