From 9df8d2f795e66c412f53c2cf2f0fab3458e08f6a Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 25 Sep 2017 21:01:52 -0700 Subject: [PATCH 1/2] Remove the params argument from IClientProxy (#946) * Remove the params argument from IClientProxy - This allows passing arrays without having to explicitly ToArray() or AsEnumerable() - Added overloads up to 10 arguments - Added tests --- samples/ChatSample/Hubs/Chat.cs | 5 +- .../IClientProxy.cs | 2 +- .../IClientProxyExtensions.cs | 175 ++++++++++++++++++ .../HubEndpointTests.cs | 42 +++++ 4 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs diff --git a/samples/ChatSample/Hubs/Chat.cs b/samples/ChatSample/Hubs/Chat.cs index ab59700c01..74a0317924 100644 --- a/samples/ChatSample/Hubs/Chat.cs +++ b/samples/ChatSample/Hubs/Chat.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.SignalR; namespace ChatSample.Hubs { @@ -23,12 +24,12 @@ namespace ChatSample.Hubs public override Task OnUsersJoined(UserDetails[] users) { - return Clients.Client(Context.ConnectionId).InvokeAsync("UsersJoined", new[] { users }); + return Clients.Client(Context.ConnectionId).InvokeAsync("UsersJoined", users); } public override Task OnUsersLeft(UserDetails[] users) { - return Clients.Client(Context.ConnectionId).InvokeAsync("UsersLeft", new[] { users }); + return Clients.Client(Context.ConnectionId).InvokeAsync("UsersLeft", users); } public async Task Send(string message) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxy.cs b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxy.cs index 3749eba811..666d46a035 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxy.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxy.cs @@ -13,6 +13,6 @@ namespace Microsoft.AspNetCore.SignalR /// name of the method to invoke /// argumetns to pass to the client /// A task that represents when the data has been sent to the client. - Task InvokeAsync(string method, params object[] args); + Task InvokeAsync(string method, object[] args); } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs new file mode 100644 index 0000000000..d4a6a3abd0 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.SignalR +{ + public static class IClientProxyExtensions + { + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1) + { + return clientProxy.InvokeAsync(method, new object[] { arg1 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// The sixth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5, arg6 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// The sixth argument + /// The seventh argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// The sixth argument + /// The seventh argument + /// The eigth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// The sixth argument + /// The seventh argument + /// The eigth argument + /// The ninth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 }); + } + + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// The first argument + /// The second argument + /// The third argument + /// The fourth argument + /// The fifth argument + /// The sixth argument + /// The seventh argument + /// The eigth argument + /// The ninth argument + /// The tenth argument + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, object arg10) + { + return clientProxy.InvokeAsync(method, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }); + } + } +} diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/HubEndpointTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/HubEndpointTests.cs index 8159f38de2..d9123e448c 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/HubEndpointTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/HubEndpointTests.cs @@ -21,6 +21,7 @@ using Moq; using MsgPack; using MsgPack.Serialization; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using Xunit; @@ -697,6 +698,42 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task SendArraySendsArrayToAllClients() + { + var serviceProvider = CreateServiceProvider(); + + var endPoint = serviceProvider.GetService>(); + + using (var firstClient = new TestClient()) + using (var secondClient = new TestClient()) + { + Task firstEndPointTask = endPoint.OnConnectedAsync(firstClient.Connection); + Task secondEndPointTask = endPoint.OnConnectedAsync(secondClient.Connection); + + await Task.WhenAll(firstClient.Connected, secondClient.Connected).OrTimeout(); + + await firstClient.SendInvocationAsync(nameof(MethodHub.SendArray)).OrTimeout(); + + foreach (var result in await Task.WhenAll( + firstClient.ReadAsync(), + secondClient.ReadAsync()).OrTimeout()) + { + var invocation = Assert.IsType(result); + Assert.Equal("Array", invocation.Target); + Assert.Single(invocation.Arguments); + var values = ((JArray)invocation.Arguments[0]).Select(t => t.Value()).ToArray(); + Assert.Equal(new int[] { 1, 2, 3 }, values); + } + + // kill the connections + firstClient.Dispose(); + secondClient.Dispose(); + + await Task.WhenAll(firstEndPointTask, secondEndPointTask).OrTimeout(); + } + } + [Theory] [MemberData(nameof(HubTypes))] public async Task SendToAllExcept(Type hubType) @@ -1570,6 +1607,11 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.All.InvokeAsync("Broadcast", new Result { Message = "test", paramName = "param" }); } + public Task SendArray() + { + return Clients.All.InvokeAsync("Array", new int[] { 1, 2, 3 }); + } + public Task TaskValueMethod() { return Task.FromResult(42); From e17cdae04664ca7b038573a3fc04e38096a0f001 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 25 Sep 2017 23:42:05 -0700 Subject: [PATCH 2/2] Added overloads from 0-n arguments (#949) - Added 0 arg overload for InvokeAsync --- .../HubConnection.cs | 18 +-- .../HubConnectionExtensions.InvokeAsync.cs | 79 ++++++++++++ ...ConnectionExtensions.InvokeAsyncGeneric.cs | 80 ++++++++++++ .../HubConnectionExtensions.SendAsync.cs | 69 ++++++++++ .../HubConnectionExtensions.StreamAsync.cs | 121 ++++++++++++++++++ .../HubConnectionExtensions.cs | 88 +------------ .../IClientProxyExtensions.cs | 11 ++ 7 files changed, 371 insertions(+), 95 deletions(-) create mode 100644 src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsync.cs create mode 100644 src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsyncGeneric.cs create mode 100644 src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.SendAsync.cs create mode 100644 src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.StreamAsync.cs diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs index d6c542fbab..0c4fb3c6d0 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs @@ -131,32 +131,32 @@ namespace Microsoft.AspNetCore.SignalR.Client _handlers.AddOrUpdate(methodName, invocationHandler, (_, __) => invocationHandler); } - public async Task> StreamAsync(string methodName, Type returnType, CancellationToken cancellationToken, params object[] args) + public async Task> StreamAsync(string methodName, Type returnType, object[] args, CancellationToken cancellationToken = default(CancellationToken)) { - return await StreamAsyncCore(methodName, returnType, cancellationToken).ForceAsync(); + return await StreamAsyncCore(methodName, returnType, args, cancellationToken).ForceAsync(); } - private async Task> StreamAsyncCore(string methodName, Type returnType, CancellationToken cancellationToken, params object[] args) + private async Task> StreamAsyncCore(string methodName, Type returnType, object[] args, CancellationToken cancellationToken) { var irq = InvocationRequest.Stream(cancellationToken, returnType, GetNextId(), _loggerFactory, out var channel); await InvokeCore(methodName, irq, args, nonBlocking: false); return channel; } - public async Task InvokeAsync(string methodName, Type returnType, CancellationToken cancellationToken, params object[] args) => - await InvokeAsyncCore(methodName, returnType, cancellationToken, args).ForceAsync(); + public async Task InvokeAsync(string methodName, Type returnType, object[] args, CancellationToken cancellationToken = default(CancellationToken)) => + await InvokeAsyncCore(methodName, returnType, args, cancellationToken).ForceAsync(); - private async Task InvokeAsyncCore(string methodName, Type returnType, CancellationToken cancellationToken, params object[] args) + private async Task InvokeAsyncCore(string methodName, Type returnType, object[] args, CancellationToken cancellationToken) { var irq = InvocationRequest.Invoke(cancellationToken, returnType, GetNextId(), _loggerFactory, out var task); await InvokeCore(methodName, irq, args, nonBlocking: false); return await task; } - public async Task SendAsync(string methodName, CancellationToken cancellationToken, params object[] args) => - await SendAsyncCore(methodName, cancellationToken, args).ForceAsync(); + public async Task SendAsync(string methodName, object[] args, CancellationToken cancellationToken = default(CancellationToken)) => + await SendAsyncCore(methodName, args, cancellationToken).ForceAsync(); - private Task SendAsyncCore(string methodName, CancellationToken cancellationToken, params object[] args) + private Task SendAsyncCore(string methodName, object[] args, CancellationToken cancellationToken) { var irq = InvocationRequest.Invoke(cancellationToken, typeof(void), GetNextId(), _loggerFactory, out _); return InvokeCore(methodName, irq, args, nonBlocking: true); diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsync.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsync.cs new file mode 100644 index 0000000000..974900aa03 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsync.cs @@ -0,0 +1,79 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.Threading; + +namespace Microsoft.AspNetCore.SignalR.Client +{ + public partial class HubConnectionExtensions + { + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, Array.Empty(), cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 }, cancellationToken); + } + + public static Task InvokeAsync(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(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object[] args, CancellationToken cancellationToken = default(CancellationToken)) + { + if (hubConnection == null) + { + throw new ArgumentNullException(nameof(hubConnection)); + } + + return hubConnection.InvokeAsync(methodName, typeof(object), args, cancellationToken); + } + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsyncGeneric.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsyncGeneric.cs new file mode 100644 index 0000000000..c59bc51f15 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.InvokeAsyncGeneric.cs @@ -0,0 +1,80 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.Threading; + +namespace Microsoft.AspNetCore.SignalR.Client +{ + public static partial class HubConnectionExtensions + { + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, Array.Empty(), cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }, cancellationToken); + } + + public static Task InvokeAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 }, cancellationToken); + } + + public static Task InvokeAsync(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(CancellationToken)) + { + return hubConnection.InvokeAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }, cancellationToken); + } + + public static async Task InvokeAsync(this HubConnection hubConnection, string methodName, object[] args, CancellationToken cancellationToken = default(CancellationToken)) + { + if (hubConnection == null) + { + throw new ArgumentNullException(nameof(hubConnection)); + } + + return (TResult)await hubConnection.InvokeAsync(methodName, typeof(TResult), args, cancellationToken); + } + + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.SendAsync.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.SendAsync.cs new file mode 100644 index 0000000000..6f0d1acf86 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.SendAsync.cs @@ -0,0 +1,69 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.SignalR.Client +{ + public static partial class HubConnectionExtensions + { + public static Task SendAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, Array.Empty(), cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }, cancellationToken); + } + + public static Task SendAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 }, cancellationToken); + } + + public static Task SendAsync(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(CancellationToken)) + { + return hubConnection.SendAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }, cancellationToken); + } + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.StreamAsync.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.StreamAsync.cs new file mode 100644 index 0000000000..267ea0e001 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.StreamAsync.cs @@ -0,0 +1,121 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Channels; + +namespace Microsoft.AspNetCore.SignalR.Client +{ + public static partial class HubConnectionExtensions + { + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, Array.Empty(), cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }, cancellationToken); + } + + public static Task> StreamAsync(this HubConnection hubConnection, string methodName, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8, object arg9, CancellationToken cancellationToken = default(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 }, cancellationToken); + } + + public static Task> StreamAsync(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(CancellationToken)) + { + return hubConnection.StreamAsync(methodName, new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 }, cancellationToken); + } + + public static async Task> StreamAsync(this HubConnection hubConnection, string methodName, object[] args, CancellationToken cancellationToken = default(CancellationToken)) + { + if (hubConnection == null) + { + throw new ArgumentNullException(nameof(hubConnection)); + } + + var inputChannel = await hubConnection.StreamAsync(methodName, typeof(TResult), args, cancellationToken); + var outputChannel = Channel.CreateUnbounded(); + + // 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.Out.TryWrite((TResult)item)) + { + if (!await outputChannel.Out.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.Out.TryComplete(ex); + } + finally + { + // This will safely no-op if the catch block above ran. + outputChannel.Out.TryComplete(); + } + } + + _ = RunChannel(); + + return outputChannel.In; + } + + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.cs index 5516415ea2..1886aaa52d 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionExtensions.cs @@ -8,95 +8,11 @@ using System.Threading.Tasks.Channels; namespace Microsoft.AspNetCore.SignalR.Client { - public static class HubConnectionExtensions + public static partial class HubConnectionExtensions { - public static Task InvokeAsync(this HubConnection hubConnection, string methodName, params object[] args) => - InvokeAsync(hubConnection, methodName, CancellationToken.None, args); - - public static Task InvokeAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken, params object[] args) - { - if (hubConnection == null) - { - throw new ArgumentNullException(nameof(hubConnection)); - } - - return hubConnection.InvokeAsync(methodName, typeof(object), cancellationToken, args); - } - - public static Task InvokeAsync(this HubConnection hubConnection, string methodName, params object[] args) => - InvokeAsync(hubConnection, methodName, CancellationToken.None, args); - - public async static Task InvokeAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken, params object[] args) - { - if (hubConnection == null) - { - throw new ArgumentNullException(nameof(hubConnection)); - } - - return (TResult)await hubConnection.InvokeAsync(methodName, typeof(TResult), cancellationToken, args); - } - - public static Task SendAsync(this HubConnection hubConnection, string methodName, params object[] args) - { - return hubConnection.SendAsync(methodName, CancellationToken.None, args); - } - - public static Task> StreamAsync(this HubConnection hubConnection, string methodName, params object[] args) => - StreamAsync(hubConnection, methodName, CancellationToken.None, args); - - public static async Task> StreamAsync(this HubConnection hubConnection, string methodName, CancellationToken cancellationToken, params object[] args) - { - if (hubConnection == null) - { - throw new ArgumentNullException(nameof(hubConnection)); - } - - var inputChannel = await hubConnection.StreamAsync(methodName, typeof(TResult), cancellationToken, args); - var outputChannel = Channel.CreateUnbounded(); - - // 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.Out.TryWrite((TResult)item)) - { - if (!await outputChannel.Out.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.Out.TryComplete(ex); - } - finally - { - // This will safely no-op if the catch block above ran. - outputChannel.Out.TryComplete(); - } - } - - _ = RunChannel(); - - return outputChannel.In; - } - private static void On(this HubConnection hubConnetion, string methodName, Type[] parameterTypes, Action handler) { - hubConnetion.On(methodName, parameterTypes, (parameters) => + hubConnetion.On(methodName, parameterTypes, (parameters) => { handler(parameters); return Task.CompletedTask; diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs index d4a6a3abd0..1d4fff5ab0 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs @@ -7,6 +7,17 @@ namespace Microsoft.AspNetCore.SignalR { public static class IClientProxyExtensions { + /// + /// Invokes a method on the connection(s) represented by the instance. + /// + /// The + /// name of the method to invoke + /// A task that represents when the data has been sent to the client. + public static Task InvokeAsync(this IClientProxy clientProxy, string method) + { + return clientProxy.InvokeAsync(method, Array.Empty()); + } + /// /// Invokes a method on the connection(s) represented by the instance. ///