22// The .NET Foundation licenses this file to you under the MIT license. 
33// See the LICENSE file in the project root for more information. 
44
5+ using  System ; 
56using  System . Data ; 
67using  System . Data . Common ; 
78using  System . Diagnostics ; 
@@ -15,6 +16,7 @@ namespace Microsoft.Data.ProviderBase
1516{ 
1617    internal  abstract  partial  class  DbConnectionFactory 
1718    { 
19+         private  static readonly  Action < Task < DbConnectionInternal > ,  object >  s_tryGetConnectionCompletedContinuation  =  TryGetConnectionCompletedContinuation ; 
1820
1921        internal  bool  TryGetConnection ( DbConnection  owningConnection ,  TaskCompletionSource < DbConnectionInternal >  retry ,  DbConnectionOptions  userOptions ,  DbConnectionInternal  oldConnection ,  out  DbConnectionInternal  connection ) 
2022        { 
@@ -82,25 +84,7 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour
8284
8385                            // now that we have an antecedent task, schedule our work when it is completed. 
8486                            // If it is a new slot or a completed task, this continuation will start right away. 
85-                             newTask  =  s_pendingOpenNonPooled [ idx ] . ContinueWith ( ( _ )  => 
86-                             { 
87-                                 Transaction  originalTransaction  =  ADP . GetCurrentTransaction ( ) ; 
88-                                 try 
89-                                 { 
90-                                     ADP . SetCurrentTransaction ( retry . Task . AsyncState  as  Transaction ) ; 
91-                                     var  newConnection  =  CreateNonPooledConnection ( owningConnection ,  poolGroup ,  userOptions ) ; 
92-                                     if  ( ( oldConnection  !=  null )  &&  ( oldConnection . State  ==  ConnectionState . Open ) ) 
93-                                     { 
94-                                         oldConnection . PrepareForReplaceConnection ( ) ; 
95-                                         oldConnection . Dispose ( ) ; 
96-                                     } 
97-                                     return  newConnection ; 
98-                                 } 
99-                                 finally 
100-                                 { 
101-                                     ADP . SetCurrentTransaction ( originalTransaction ) ; 
102-                                 } 
103-                             } ,  cancellationTokenSource . Token ,  TaskContinuationOptions . LongRunning ,  TaskScheduler . Default ) ; 
87+                             newTask  =  CreateReplaceConnectionContinuation ( s_pendingOpenNonPooled [ idx ] ,  owningConnection ,  retry ,  userOptions ,  oldConnection ,  poolGroup ,  cancellationTokenSource ) ; 
10488
10589                            // Place this new task in the slot so any future work will be queued behind it 
10690                            s_pendingOpenNonPooled [ idx ]  =  newTask ; 
@@ -114,29 +98,11 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour
11498                        } 
11599
116100                        // once the task is done, propagate the final results to the original caller 
117-                         newTask . ContinueWith ( ( task )  => 
118-                         { 
119-                             cancellationTokenSource . Dispose ( ) ; 
120-                             if  ( task . IsCanceled ) 
121-                             { 
122-                                 retry . TrySetException ( ADP . ExceptionWithStackTrace ( ADP . NonPooledOpenTimeout ( ) ) ) ; 
123-                             } 
124-                             else  if  ( task . IsFaulted ) 
125-                             { 
126-                                 retry . TrySetException ( task . Exception . InnerException ) ; 
127-                             } 
128-                             else 
129-                             { 
130-                                 if  ( ! retry . TrySetResult ( task . Result ) ) 
131-                                 { 
132-                                     // The outer TaskCompletionSource was already completed 
133-                                     // Which means that we don't know if someone has messed with the outer connection in the middle of creation 
134-                                     // So the best thing to do now is to destroy the newly created connection 
135-                                     task . Result . DoomThisConnection ( ) ; 
136-                                     task . Result . Dispose ( ) ; 
137-                                 } 
138-                             } 
139-                         } ,  TaskScheduler . Default ) ; 
101+                         newTask . ContinueWith ( 
102+                             continuationAction :  s_tryGetConnectionCompletedContinuation ,  
103+                             state :  Tuple . Create ( cancellationTokenSource ,  retry ) , 
104+                             scheduler :  TaskScheduler . Default 
105+                         ) ; 
140106
141107                        return  false ; 
142108                    } 
@@ -188,5 +154,62 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour
188154
189155            return  true ; 
190156        } 
157+ 
158+         private  Task < DbConnectionInternal >  CreateReplaceConnectionContinuation ( Task < DbConnectionInternal >  task ,  DbConnection  owningConnection ,  TaskCompletionSource < DbConnectionInternal >  retry ,  DbConnectionOptions  userOptions ,  DbConnectionInternal  oldConnection ,  DbConnectionPoolGroup  poolGroup ,  CancellationTokenSource  cancellationTokenSource ) 
159+         { 
160+             return  task . ContinueWith ( 
161+                 ( _ )  => 
162+                 { 
163+                     Transaction  originalTransaction  =  ADP . GetCurrentTransaction ( ) ; 
164+                     try 
165+                     { 
166+                         ADP . SetCurrentTransaction ( retry . Task . AsyncState  as  Transaction ) ; 
167+                         var  newConnection  =  CreateNonPooledConnection ( owningConnection ,  poolGroup ,  userOptions ) ; 
168+                         if  ( ( oldConnection  !=  null )  &&  ( oldConnection . State  ==  ConnectionState . Open ) ) 
169+                         { 
170+                             oldConnection . PrepareForReplaceConnection ( ) ; 
171+                             oldConnection . Dispose ( ) ; 
172+                         } 
173+                         return  newConnection ; 
174+                     } 
175+                     finally 
176+                     { 
177+                         ADP . SetCurrentTransaction ( originalTransaction ) ; 
178+                     } 
179+                 } , 
180+                 cancellationTokenSource . Token , 
181+                 TaskContinuationOptions . LongRunning , 
182+                 TaskScheduler . Default 
183+             ) ; 
184+         } 
185+ 
186+         private  static void  TryGetConnectionCompletedContinuation ( Task < DbConnectionInternal >  task ,  object  state ) 
187+         { 
188+             Tuple < CancellationTokenSource ,  TaskCompletionSource < DbConnectionInternal > >  parameters  =  ( Tuple < CancellationTokenSource ,  TaskCompletionSource < DbConnectionInternal > > ) state ; 
189+             CancellationTokenSource  source  =  parameters . Item1 ; 
190+             source . Dispose ( ) ; 
191+ 
192+             TaskCompletionSource < DbConnectionInternal >  retryCompletionSource  =  parameters . Item2 ; 
193+ 
194+             if  ( task . IsCanceled ) 
195+             { 
196+                 retryCompletionSource . TrySetException ( ADP . ExceptionWithStackTrace ( ADP . NonPooledOpenTimeout ( ) ) ) ; 
197+             } 
198+             else  if  ( task . IsFaulted ) 
199+             { 
200+                 retryCompletionSource . TrySetException ( task . Exception . InnerException ) ; 
201+             } 
202+             else 
203+             { 
204+                 if  ( ! retryCompletionSource . TrySetResult ( task . Result ) ) 
205+                 { 
206+                     // The outer TaskCompletionSource was already completed 
207+                     // Which means that we don't know if someone has messed with the outer connection in the middle of creation 
208+                     // So the best thing to do now is to destroy the newly created connection 
209+                     task . Result . DoomThisConnection ( ) ; 
210+                     task . Result . Dispose ( ) ; 
211+                 } 
212+             } 
213+         } 
191214    } 
192215} 
0 commit comments