private async Task<int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(this, WebSocketValidate.GetTraceMsgForParameters(offset, count, cancellationToken));
}
CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration();
int bytesRead = 0;
try
{
if (cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false);
}
if (!_inOpaqueMode)
{
bytesRead = await _inputStream.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow<int>();
}
else
{
#if DEBUG
// When using fast path only one outstanding read is permitted. By switching into opaque mode
// via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
// caller takes responsibility for enforcing this constraint.
Debug.Assert(Interlocked.Increment(ref _outstandingOperations._reads) == 1,
"Only one outstanding read allowed at any given time.");
#endif
_readTaskCompletionSource = new TaskCompletionSource<int>();
_readEventArgs.SetBuffer(buffer, offset, count);
if (!ReadAsyncFast(_readEventArgs))
{
if (_readEventArgs.Exception != null)
{
throw _readEventArgs.Exception;
}
bytesRead = _readEventArgs.BytesTransferred;
}
else
{
bytesRead = await _readTaskCompletionSource.Task.SuppressContextFlow<int>();
}
}
}
catch (Exception error)
{
if (s_CanHandleException(error))
{
cancellationToken.ThrowIfCancellationRequested();
}
throw;
}
finally
{
cancellationTokenRegistration.Dispose();
if (NetEventSource.IsEnabled)
{
NetEventSource.Exit(this, bytesRead);
}
}
return bytesRead;
}