/// <inheritdoc /> public override async Task WriteAsync(Message message, CancellationToken cancellationToken) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (DisposalToken.IsCancellationRequested) { throw new ObjectDisposedException(nameof(ByLineTextMessageWriter)); } cancellationToken.ThrowIfCancellationRequested(); DisposalToken.ThrowIfCancellationRequested(); using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, DisposalToken)) { var linkedToken = linkedTokenSource.Token; var content = message.ToString(); await writerSemaphore.WaitAsync(linkedToken); try { await Writer.WriteLineAsync(content); linkedToken.ThrowIfCancellationRequested(); if (Delimiter != null) { await Writer.WriteLineAsync(Delimiter); linkedToken.ThrowIfCancellationRequested(); } await Writer.FlushAsync(); } catch (ObjectDisposedException) { // Throws OperationCanceledException if the cancellation has already been requested. linkedToken.ThrowIfCancellationRequested(); throw; } finally { if (!DisposalToken.IsCancellationRequested) { writerSemaphore.Release(); } } } }
private bool TryTranslateException(Exception exception, CancellationToken cancellationToken1, CancellationToken cancellationToken2) { // Consumers treat cancellation due their specified token being cancelled differently from cancellation // due our instance being disposed. Because we wrap the two in a source, the resulting exception // contains it instead of the one that was actually cancelled. if (exception is OperationCanceledException) { cancellationToken1.ThrowIfCancellationRequested(); cancellationToken2.ThrowIfCancellationRequested(); } if (exception is ObjectDisposedException && DisposalToken.IsCancellationRequested) { // There's a tiny chance that between checking the cancellation token (wrapping DisposalToken) // and checking if the underlying SemaphoreSlim has been disposed, that dispose for this instance // (and hence _semaphore) has been run. Handle that and just treat it as a cancellation. DisposalToken.ThrowIfCancellationRequested(); } return(false); }