@@ -23,6 +23,7 @@ internal class SNIPacket : IDisposable, IEquatable<SNIPacket>
2323
2424 private ArrayPool < byte > _arrayPool = ArrayPool < byte > . Shared ;
2525 private bool _isBufferFromArrayPool = false ;
26+ private ValueTask _asyncOperation ;
2627
2728 public SNIPacket ( ) { }
2829
@@ -238,6 +239,7 @@ public void Reset()
238239 _offset = 0 ;
239240 _description = null ;
240241 _completionCallback = null ;
242+ _asyncOperation = default ;
241243 }
242244
243245 /// <summary>
@@ -247,37 +249,50 @@ public void Reset()
247249 /// <param name="callback">Completion callback</param>
248250 public void ReadFromStreamAsync ( Stream stream , SNIAsyncCallback callback )
249251 {
250- bool error = false ;
251-
252- stream . ReadAsync ( _data , 0 , _capacity , CancellationToken . None ) . ContinueWith ( t =>
252+ // Treat local function as a static and pass all params otherwise as async will allocate
253+ async ValueTask ReadFromStreamAsync ( SNIPacket packet , SNIAsyncCallback cb , ValueTask < int > valueTask )
253254 {
254- Exception e = t . Exception ? . InnerException ;
255- if ( e != null )
255+ bool error = false ;
256+ try
256257 {
257- SNILoadHandle . SingletonInstance . LastError = new SNIError ( SNIProviders . TCP_PROV , SNICommon . InternalExceptionError , e ) ;
258- error = true ;
259- }
260- else
261- {
262- _length = t . Result ;
263-
264- if ( _length == 0 )
258+ packet . _length = await valueTask . ConfigureAwait ( false ) ;
259+ if ( packet . _length == 0 )
265260 {
266261 SNILoadHandle . SingletonInstance . LastError = new SNIError ( SNIProviders . TCP_PROV , 0 , SNICommon . ConnTerminatedError , string . Empty ) ;
267262 error = true ;
268263 }
269264 }
265+ catch ( Exception ex )
266+ {
267+ SNILoadHandle . SingletonInstance . LastError = new SNIError ( SNIProviders . TCP_PROV , SNICommon . InternalExceptionError , ex ) ;
268+ error = true ;
269+ }
270270
271271 if ( error )
272272 {
273- Release ( ) ;
273+ packet . Release ( ) ;
274+ }
275+
276+ cb ( packet , error ? TdsEnums . SNI_ERROR : TdsEnums . SNI_SUCCESS ) ;
277+ }
278+
279+ ValueTask < int > vt = stream . ReadAsync ( new Memory < byte > ( _data , 0 , _capacity ) , CancellationToken . None ) ;
280+
281+ if ( vt . IsCompletedSuccessfully )
282+ {
283+ _length = vt . Result ;
284+ // Zero length to go via async local function as is error condition
285+ if ( _length > 0 )
286+ {
287+ callback ( this , TdsEnums . SNI_SUCCESS ) ;
288+
289+ // Completed
290+ return ;
274291 }
292+ }
275293
276- callback ( this , error ? TdsEnums . SNI_ERROR : TdsEnums . SNI_SUCCESS ) ;
277- } ,
278- CancellationToken . None ,
279- TaskContinuationOptions . DenyChildAttach ,
280- TaskScheduler . Default ) ;
294+ // Not complete or error call the async local function to complete
295+ _asyncOperation = ReadFromStreamAsync ( this , callback , vt ) ;
281296 }
282297
283298 /// <summary>
@@ -302,24 +317,47 @@ public void WriteToStream(Stream stream)
302317 /// Write data to a stream asynchronously
303318 /// </summary>
304319 /// <param name="stream">Stream to write to</param>
305- public async void WriteToStreamAsync ( Stream stream , SNIAsyncCallback callback , SNIProviders provider , bool disposeAfterWriteAsync = false )
320+ public void WriteToStreamAsync ( Stream stream , SNIAsyncCallback callback , SNIProviders provider , bool disposeAfterWriteAsync = false )
306321 {
307- uint status = TdsEnums . SNI_SUCCESS ;
308- try
322+ // Treat local function as a static and pass all params otherwise as async will allocate
323+ async ValueTask WriteToStreamAsync ( SNIPacket packet , SNIAsyncCallback cb , SNIProviders providers , bool disposeAfter , ValueTask valueTask )
309324 {
310- await stream . WriteAsync ( _data , 0 , _length , CancellationToken . None ) . ConfigureAwait ( false ) ;
311- }
312- catch ( Exception e )
313- {
314- SNILoadHandle . SingletonInstance . LastError = new SNIError ( provider , SNICommon . InternalExceptionError , e ) ;
315- status = TdsEnums . SNI_ERROR ;
325+ uint status = TdsEnums . SNI_SUCCESS ;
326+ try
327+ {
328+ await valueTask . ConfigureAwait ( false ) ;
329+ }
330+ catch ( Exception e )
331+ {
332+ SNILoadHandle . SingletonInstance . LastError = new SNIError ( providers , SNICommon . InternalExceptionError , e ) ;
333+ status = TdsEnums . SNI_ERROR ;
334+ }
335+
336+ cb ( packet , status ) ;
337+
338+ if ( disposeAfter )
339+ {
340+ packet . Dispose ( ) ;
341+ }
316342 }
317- callback ( this , status ) ;
318343
319- if ( disposeAfterWriteAsync )
344+ ValueTask vt = stream . WriteAsync ( new Memory < byte > ( _data , 0 , _length ) , CancellationToken . None ) ;
345+
346+ if ( vt . IsCompletedSuccessfully )
320347 {
321- Dispose ( ) ;
348+ callback ( this , TdsEnums . SNI_SUCCESS ) ;
349+
350+ if ( disposeAfterWriteAsync )
351+ {
352+ Dispose ( ) ;
353+ }
354+
355+ // Completed
356+ return ;
322357 }
358+
359+ // Not complete or error call the async local function to complete
360+ _asyncOperation = WriteToStreamAsync ( this , callback , provider , disposeAfterWriteAsync , vt ) ;
323361 }
324362
325363 /// <summary>
0 commit comments