@@ -4397,6 +4397,7 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn
4397
4397
public override Task < bool > NextResultAsync ( CancellationToken cancellationToken )
4398
4398
{
4399
4399
using ( TryEventScope . Create ( "SqlDataReader.NextResultAsync | API | Object Id {0}" , ObjectID ) )
4400
+ using ( var registrationHolder = new DisposableTemporaryOnStack < CancellationTokenRegistration > ( ) )
4400
4401
{
4401
4402
TaskCompletionSource < bool > source = new TaskCompletionSource < bool > ( ) ;
4402
4403
@@ -4406,15 +4407,14 @@ public override Task<bool> NextResultAsync(CancellationToken cancellationToken)
4406
4407
return source . Task ;
4407
4408
}
4408
4409
4409
- IDisposable registration = null ;
4410
4410
if ( cancellationToken . CanBeCanceled )
4411
4411
{
4412
4412
if ( cancellationToken . IsCancellationRequested )
4413
4413
{
4414
4414
source . SetCanceled ( ) ;
4415
4415
return source . Task ;
4416
4416
}
4417
- registration = cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ;
4417
+ registrationHolder . Set ( cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ) ;
4418
4418
}
4419
4419
4420
4420
Task original = Interlocked . CompareExchange ( ref _currentTask , source . Task , null ) ;
@@ -4432,7 +4432,7 @@ public override Task<bool> NextResultAsync(CancellationToken cancellationToken)
4432
4432
return source . Task ;
4433
4433
}
4434
4434
4435
- return InvokeAsyncCall ( new HasNextResultAsyncCallContext ( this , source , registration ) ) ;
4435
+ return InvokeAsyncCall ( new HasNextResultAsyncCallContext ( this , source , registrationHolder . Take ( ) ) ) ;
4436
4436
}
4437
4437
}
4438
4438
@@ -4727,17 +4727,17 @@ out bytesRead
4727
4727
public override Task < bool > ReadAsync ( CancellationToken cancellationToken )
4728
4728
{
4729
4729
using ( TryEventScope . Create ( "SqlDataReader.ReadAsync | API | Object Id {0}" , ObjectID ) )
4730
+ using ( var registrationHolder = new DisposableTemporaryOnStack < CancellationTokenRegistration > ( ) )
4730
4731
{
4731
4732
if ( IsClosed )
4732
4733
{
4733
4734
return Task . FromException < bool > ( ADP . ExceptionWithStackTrace ( ADP . DataReaderClosed ( ) ) ) ;
4734
4735
}
4735
4736
4736
4737
// Register first to catch any already expired tokens to be able to trigger cancellation event.
4737
- IDisposable registration = null ;
4738
4738
if ( cancellationToken . CanBeCanceled )
4739
4739
{
4740
- registration = cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ;
4740
+ registrationHolder . Set ( cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ) ;
4741
4741
}
4742
4742
4743
4743
// If user's token is canceled, return a canceled task
@@ -4850,7 +4850,7 @@ public override Task<bool> ReadAsync(CancellationToken cancellationToken)
4850
4850
4851
4851
Debug . Assert ( context . Reader == null && context . Source == null && context . Disposable == null , "cached ReadAsyncCallContext was not properly disposed" ) ;
4852
4852
4853
- context . Set ( this , source , registration ) ;
4853
+ context . Set ( this , source , registrationHolder . Take ( ) ) ;
4854
4854
context . _hasMoreData = more ;
4855
4855
context . _hasReadRowToken = rowTokenRead ;
4856
4856
@@ -4988,49 +4988,51 @@ override public Task<bool> IsDBNullAsync(int i, CancellationToken cancellationTo
4988
4988
return Task . FromException < bool > ( ex ) ;
4989
4989
}
4990
4990
4991
- // Setup and check for pending task
4992
- TaskCompletionSource < bool > source = new TaskCompletionSource < bool > ( ) ;
4993
- Task original = Interlocked . CompareExchange ( ref _currentTask , source . Task , null ) ;
4994
- if ( original != null )
4991
+ using ( var registrationHolder = new DisposableTemporaryOnStack < CancellationTokenRegistration > ( ) )
4995
4992
{
4996
- source . SetException ( ADP . ExceptionWithStackTrace ( ADP . AsyncOperationPending ( ) ) ) ;
4997
- return source . Task ;
4998
- }
4993
+ // Setup and check for pending task
4994
+ TaskCompletionSource < bool > source = new TaskCompletionSource < bool > ( ) ;
4995
+ Task original = Interlocked . CompareExchange ( ref _currentTask , source . Task , null ) ;
4996
+ if ( original != null )
4997
+ {
4998
+ source . SetException ( ADP . ExceptionWithStackTrace ( ADP . AsyncOperationPending ( ) ) ) ;
4999
+ return source . Task ;
5000
+ }
4999
5001
5000
- // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
5001
- if ( _cancelAsyncOnCloseToken . IsCancellationRequested )
5002
- {
5003
- source . SetCanceled ( ) ;
5004
- _currentTask = null ;
5005
- return source . Task ;
5006
- }
5002
+ // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
5003
+ if ( _cancelAsyncOnCloseToken . IsCancellationRequested )
5004
+ {
5005
+ source . SetCanceled ( ) ;
5006
+ _currentTask = null ;
5007
+ return source . Task ;
5008
+ }
5007
5009
5008
- // Setup cancellations
5009
- IDisposable registration = null ;
5010
- if ( cancellationToken . CanBeCanceled )
5011
- {
5012
- registration = cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ;
5013
- }
5010
+ // Setup cancellations
5011
+ if ( cancellationToken . CanBeCanceled )
5012
+ {
5013
+ registrationHolder . Set ( cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ) ;
5014
+ }
5014
5015
5015
- IsDBNullAsyncCallContext context = null ;
5016
- if ( _connection ? . InnerConnection is SqlInternalConnection sqlInternalConnection )
5017
- {
5018
- context = Interlocked . Exchange ( ref sqlInternalConnection . CachedDataReaderIsDBNullContext , null ) ;
5019
- }
5020
- if ( context is null )
5021
- {
5022
- context = new IsDBNullAsyncCallContext ( ) ;
5023
- }
5016
+ IsDBNullAsyncCallContext context = null ;
5017
+ if ( _connection ? . InnerConnection is SqlInternalConnection sqlInternalConnection )
5018
+ {
5019
+ context = Interlocked . Exchange ( ref sqlInternalConnection . CachedDataReaderIsDBNullContext , null ) ;
5020
+ }
5021
+ if ( context is null )
5022
+ {
5023
+ context = new IsDBNullAsyncCallContext ( ) ;
5024
+ }
5024
5025
5025
- Debug . Assert ( context . Reader == null && context . Source == null && context . Disposable == null , "cached ISDBNullAsync context not properly disposed" ) ;
5026
+ Debug . Assert ( context . Reader == null && context . Source == null && context . Disposable == default , "cached ISDBNullAsync context not properly disposed" ) ;
5026
5027
5027
- context . Set ( this , source , registration ) ;
5028
- context . _columnIndex = i ;
5028
+ context . Set ( this , source , registrationHolder . Take ( ) ) ;
5029
+ context . _columnIndex = i ;
5029
5030
5030
- // Setup async
5031
- PrepareAsyncInvocation ( useSnapshot : true ) ;
5031
+ // Setup async
5032
+ PrepareAsyncInvocation ( useSnapshot : true ) ;
5032
5033
5033
- return InvokeAsyncCall ( context ) ;
5034
+ return InvokeAsyncCall ( context ) ;
5035
+ }
5034
5036
}
5035
5037
}
5036
5038
@@ -5135,37 +5137,39 @@ override public Task<T> GetFieldValueAsync<T>(int i, CancellationToken cancellat
5135
5137
return Task . FromException < T > ( ex ) ;
5136
5138
}
5137
5139
5138
- // Setup and check for pending task
5139
- TaskCompletionSource < T > source = new TaskCompletionSource < T > ( ) ;
5140
- Task original = Interlocked . CompareExchange ( ref _currentTask , source . Task , null ) ;
5141
- if ( original != null )
5140
+ using ( var registrationHolder = new DisposableTemporaryOnStack < CancellationTokenRegistration > ( ) )
5142
5141
{
5143
- source . SetException ( ADP . ExceptionWithStackTrace ( ADP . AsyncOperationPending ( ) ) ) ;
5144
- return source . Task ;
5145
- }
5142
+ // Setup and check for pending task
5143
+ TaskCompletionSource < T > source = new TaskCompletionSource < T > ( ) ;
5144
+ Task original = Interlocked . CompareExchange ( ref _currentTask , source . Task , null ) ;
5145
+ if ( original != null )
5146
+ {
5147
+ source . SetException ( ADP . ExceptionWithStackTrace ( ADP . AsyncOperationPending ( ) ) ) ;
5148
+ return source . Task ;
5149
+ }
5146
5150
5147
- // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
5148
- if ( _cancelAsyncOnCloseToken . IsCancellationRequested )
5149
- {
5150
- source . SetCanceled ( ) ;
5151
- _currentTask = null ;
5152
- return source . Task ;
5153
- }
5151
+ // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
5152
+ if ( _cancelAsyncOnCloseToken . IsCancellationRequested )
5153
+ {
5154
+ source . SetCanceled ( ) ;
5155
+ _currentTask = null ;
5156
+ return source . Task ;
5157
+ }
5154
5158
5155
- // Setup cancellations
5156
- IDisposable registration = null ;
5157
- if ( cancellationToken . CanBeCanceled )
5158
- {
5159
- registration = cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ;
5160
- }
5159
+ // Setup cancellations
5160
+ if ( cancellationToken . CanBeCanceled )
5161
+ {
5162
+ registrationHolder . Set ( cancellationToken . Register ( SqlCommand . s_cancelIgnoreFailure , _command ) ) ;
5163
+ }
5161
5164
5162
- // Setup async
5163
- PrepareAsyncInvocation ( useSnapshot : true ) ;
5165
+ // Setup async
5166
+ PrepareAsyncInvocation ( useSnapshot : true ) ;
5164
5167
5165
- GetFieldValueAsyncCallContext < T > context = new GetFieldValueAsyncCallContext < T > ( this , source , registration ) ;
5166
- context . _columnIndex = i ;
5168
+ GetFieldValueAsyncCallContext < T > context = new GetFieldValueAsyncCallContext < T > ( this , source , registrationHolder . Take ( ) ) ;
5169
+ context . _columnIndex = i ;
5167
5170
5168
- return InvokeAsyncCall ( context ) ;
5171
+ return InvokeAsyncCall ( context ) ;
5172
+ }
5169
5173
}
5170
5174
5171
5175
private static Task < T > GetFieldValueAsyncExecute < T > ( Task task , object state )
0 commit comments