@@ -697,6 +697,10 @@ private void LaunchStreams(ConnectionState connectionState, Dictionary<string, o
697
697
return ;
698
698
}
699
699
700
+ _state . AssertInConnectionLock ( ) ;
701
+ // It's safe to access connectionState.UploadStreamToken as we still have the connection lock
702
+ var cts = CancellationTokenSource . CreateLinkedTokenSource ( connectionState . UploadStreamToken , cancellationToken ) ;
703
+
700
704
foreach ( var kvp in readers )
701
705
{
702
706
var reader = kvp . Value ;
@@ -708,19 +712,19 @@ private void LaunchStreams(ConnectionState connectionState, Dictionary<string, o
708
712
{
709
713
_ = _sendIAsyncStreamItemsMethod
710
714
. MakeGenericMethod ( reader . GetType ( ) . GetInterface ( "IAsyncEnumerable`1" ) ! . GetGenericArguments ( ) )
711
- . Invoke ( this , new object [ ] { connectionState , kvp . Key . ToString ( ) , reader , cancellationToken } ) ;
715
+ . Invoke ( this , new object [ ] { connectionState , kvp . Key . ToString ( ) , reader , cts } ) ;
712
716
continue ;
713
717
}
714
718
_ = _sendStreamItemsMethod
715
719
. MakeGenericMethod ( reader . GetType ( ) . GetGenericArguments ( ) )
716
- . Invoke ( this , new object [ ] { connectionState , kvp . Key . ToString ( ) , reader , cancellationToken } ) ;
720
+ . Invoke ( this , new object [ ] { connectionState , kvp . Key . ToString ( ) , reader , cts } ) ;
717
721
}
718
722
}
719
723
720
724
// this is called via reflection using the `_sendStreamItems` field
721
- private Task SendStreamItems < T > ( ConnectionState connectionState , string streamId , ChannelReader < T > reader , CancellationToken token )
725
+ private Task SendStreamItems < T > ( ConnectionState connectionState , string streamId , ChannelReader < T > reader , CancellationTokenSource tokenSource )
722
726
{
723
- async Task ReadChannelStream ( CancellationTokenSource tokenSource )
727
+ async Task ReadChannelStream ( )
724
728
{
725
729
while ( await reader . WaitToReadAsync ( tokenSource . Token ) )
726
730
{
@@ -732,13 +736,13 @@ async Task ReadChannelStream(CancellationTokenSource tokenSource)
732
736
}
733
737
}
734
738
735
- return CommonStreaming ( connectionState , streamId , token , ReadChannelStream ) ;
739
+ return CommonStreaming ( connectionState , streamId , ReadChannelStream ) ;
736
740
}
737
741
738
742
// this is called via reflection using the `_sendIAsyncStreamItemsMethod` field
739
- private Task SendIAsyncEnumerableStreamItems < T > ( ConnectionState connectionState , string streamId , IAsyncEnumerable < T > stream , CancellationToken token )
743
+ private Task SendIAsyncEnumerableStreamItems < T > ( ConnectionState connectionState , string streamId , IAsyncEnumerable < T > stream , CancellationTokenSource tokenSource )
740
744
{
741
- async Task ReadAsyncEnumerableStream ( CancellationTokenSource tokenSource )
745
+ async Task ReadAsyncEnumerableStream ( )
742
746
{
743
747
var streamValues = AsyncEnumerableAdapters . MakeCancelableTypedAsyncEnumerable ( stream , tokenSource ) ;
744
748
@@ -749,25 +753,26 @@ async Task ReadAsyncEnumerableStream(CancellationTokenSource tokenSource)
749
753
}
750
754
}
751
755
752
- return CommonStreaming ( connectionState , streamId , token , ReadAsyncEnumerableStream ) ;
756
+ return CommonStreaming ( connectionState , streamId , ReadAsyncEnumerableStream ) ;
753
757
}
754
758
755
- private async Task CommonStreaming ( ConnectionState connectionState , string streamId , CancellationToken token , Func < CancellationTokenSource , Task > createAndConsumeStream )
759
+ private async Task CommonStreaming ( ConnectionState connectionState , string streamId , Func < Task > createAndConsumeStream )
756
760
{
757
- // It's safe to access connectionState.UploadStreamToken as we still have the connection lock
758
- _state . AssertInConnectionLock ( ) ;
759
- var cts = CancellationTokenSource . CreateLinkedTokenSource ( connectionState . UploadStreamToken , token ) ;
760
-
761
761
Log . StartingStream ( _logger , streamId ) ;
762
762
string ? responseError = null ;
763
763
try
764
764
{
765
- await createAndConsumeStream ( cts ) ;
765
+ await createAndConsumeStream ( ) ;
766
766
}
767
767
catch ( OperationCanceledException )
768
768
{
769
769
Log . CancelingStream ( _logger , streamId ) ;
770
- responseError = $ "Stream canceled by client.";
770
+ responseError = "Stream canceled by client." ;
771
+ }
772
+ catch ( Exception ex )
773
+ {
774
+ Log . ErroredStream ( _logger , streamId , ex ) ;
775
+ responseError = $ "Stream errored by client: '{ ex } '";
771
776
}
772
777
773
778
Log . CompletingStream ( _logger , streamId ) ;
0 commit comments