public static async Task <ChannelReader <TResult> > StreamAsChannelCoreAsync <TResult>(this HubConnection hubConnection, string methodName, object[] args, CancellationToken cancellationToken = default) { if (hubConnection == null) { throw new ArgumentNullException(nameof(hubConnection)); } var inputChannel = await hubConnection.StreamAsChannelCoreAsync(methodName, typeof(TResult), args, cancellationToken); var outputChannel = Channel.CreateUnbounded <TResult>(); // Local function to provide a way to run async code as fire-and-forget // The output channel is how we signal completion to the caller. async Task RunChannel() { try { while (await inputChannel.WaitToReadAsync()) { while (inputChannel.TryRead(out var item)) { while (!outputChannel.Writer.TryWrite((TResult)item)) { if (!await outputChannel.Writer.WaitToWriteAsync()) { // Failed to write to the output channel because it was closed. Nothing really we can do but abort here. return; } } } } // Manifest any errors in the completion task await inputChannel.Completion; } catch (Exception ex) { outputChannel.Writer.TryComplete(ex); } finally { // This will safely no-op if the catch block above ran. outputChannel.Writer.TryComplete(); } } _ = RunChannel(); return(outputChannel.Reader); }
/// <summary> /// Invokes a streaming hub method on the server using the specified method name, return type and arguments. /// </summary> /// <typeparam name="TResult">The return type of the streaming server method.</typeparam> /// <param name="hubConnection">The hub connection.</param> /// <param name="methodName">The name of the server method to invoke.</param> /// <param name="args">The arguments used to invoke the server method.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None" />.</param> /// <returns> /// A <see cref="Task{TResult}"/> that represents the asynchronous invoke. /// The <see cref="Task{TResult}.Result"/> property returns a <see cref="ChannelReader{T}"/> for the streamed hub method values. /// </returns> public static async Task <ChannelReader <TResult> > StreamAsChannelCoreAsync <TResult>(this HubConnection hubConnection, string methodName, object?[] args, CancellationToken cancellationToken = default) { if (hubConnection == null) { throw new ArgumentNullException(nameof(hubConnection)); } var inputChannel = await hubConnection.StreamAsChannelCoreAsync(methodName, typeof(TResult), args, cancellationToken); var outputChannel = Channel.CreateUnbounded <TResult>(); // Intentionally avoid passing the CancellationToken to RunChannel. The token is only meant to cancel the intial setup, not the enumeration. _ = RunChannel(inputChannel, outputChannel); return(outputChannel.Reader); }
public static Task <ChannelReader <TResult> > StreamAsChannelAsync <TResult>(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, object arg10, CancellationToken cancellationToken = default) { return(hubConnection.StreamAsChannelCoreAsync <TResult>(methodName, new[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }, cancellationToken)); }
public static Task <ChannelReader <TResult> > StreamAsChannelAsync <TResult>(this HubConnection hubConnection, string methodName, object arg1, CancellationToken cancellationToken = default) { return(hubConnection.StreamAsChannelCoreAsync <TResult>(methodName, new[] { arg1 }, cancellationToken)); }
public static Task <ChannelReader <TResult> > StreamAsChannelAsync <TResult>(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken = default) { return(hubConnection.StreamAsChannelCoreAsync <TResult>(methodName, Array.Empty <object>(), cancellationToken)); }