diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionExtensions.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionExtensions.cs
index 47e87549f4..fc24655655 100644
--- a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionExtensions.cs
+++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionExtensions.cs
@@ -242,5 +242,210 @@ namespace Microsoft.AspNetCore.SignalR.Client
return currentHandler(parameters);
}, handler);
}
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName, Type.EmptyTypes, args => handler());
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1) },
+ args => handler((T1)args[0]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2) },
+ args => handler((T1)args[0], (T2)args[1]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The fourth argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The fourth argument type.
+ /// The fifth argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3], (T5)args[4]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The fourth argument type.
+ /// The fifth argument type.
+ /// The sixth argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3], (T5)args[4], (T6)args[5]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The fourth argument type.
+ /// The fifth argument type.
+ /// The sixth argument type.
+ /// The seventh argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3], (T5)args[4], (T6)args[5], (T7)args[6]));
+ }
+
+ ///
+ /// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
+ ///
+ /// The first argument type.
+ /// The second argument type.
+ /// The third argument type.
+ /// The fourth argument type.
+ /// The fifth argument type.
+ /// The sixth argument type.
+ /// The seventh argument type.
+ /// The eighth argument type.
+ /// The hub connection.
+ /// The name of the hub method to define.
+ /// The handler that will be raised when the hub method is invoked.
+ /// A subscription that can be disposed to unsubscribe from the hub method.
+ public static IDisposable On(this HubConnection hubConnection, string methodName, Func handler)
+ {
+ if (hubConnection == null)
+ {
+ throw new ArgumentNullException(nameof(hubConnection));
+ }
+
+ return hubConnection.On(methodName,
+ new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8) },
+ args => handler((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3], (T5)args[4], (T6)args[5], (T7)args[6], (T8)args[7]));
+ }
}
}
diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.Extensions.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.Extensions.cs
index cf6fa8e64d..24e8eb88bf 100644
--- a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.Extensions.cs
+++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.Extensions.cs
@@ -20,13 +20,39 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
new object[0]);
}
+ [Fact]
+ public async Task OnAsync()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ () =>
+ {
+ tcs.SetResult(new object[0]);
+ return Task.CompletedTask;
+ }),
+ new object[0]);
+ }
+
[Fact]
public async Task OnT1()
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- r => tcs.SetResult(new object[] {r})),
- new object[] {42});
+ r => tcs.SetResult(new object[] { r })),
+ new object[] { 42 });
+ }
+
+ [Fact]
+ public async Task OnT1Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ r =>
+ {
+ tcs.SetResult(new object[] { r });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42 });
}
[Fact]
@@ -34,8 +60,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2) => tcs.SetResult(new object[] {r1, r2})),
- new object[] {42, "abc"});
+ (r1, r2) => tcs.SetResult(new object[] { r1, r2 })),
+ new object[] { 42, "abc" });
+ }
+
+ [Fact]
+ public async Task OnT2Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2) =>
+ {
+ tcs.SetResult(new object[] { r1, r2 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc" });
}
[Fact]
@@ -43,8 +82,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3) => tcs.SetResult(new object[] {r1, r2, r3})),
- new object[] {42, "abc", 24.0f});
+ (r1, r2, r3) => tcs.SetResult(new object[] { r1, r2, r3 })),
+ new object[] { 42, "abc", 24.0f });
+ }
+
+ [Fact]
+ public async Task OnT3Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f });
}
[Fact]
@@ -52,8 +104,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3, r4) => tcs.SetResult(new object[] {r1, r2, r3, r4})),
- new object[] {42, "abc", 24.0f, 10d});
+ (r1, r2, r3, r4) => tcs.SetResult(new object[] { r1, r2, r3, r4 })),
+ new object[] { 42, "abc", 24.0f, 10d });
+ }
+
+ [Fact]
+ public async Task OnT4Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3, r4) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3, r4 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f, 10d });
}
[Fact]
@@ -61,8 +126,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3, r4, r5) => tcs.SetResult(new object[] {r1, r2, r3, r4, r5})),
- new object[] {42, "abc", 24.0f, 10d, "123"});
+ (r1, r2, r3, r4, r5) => tcs.SetResult(new object[] { r1, r2, r3, r4, r5 })),
+ new object[] { 42, "abc", 24.0f, 10d, "123" });
+ }
+
+ [Fact]
+ public async Task OnT5Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3, r4, r5) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3, r4, r5 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f, 10d, "123" });
}
[Fact]
@@ -70,8 +148,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3, r4, r5, r6) => tcs.SetResult(new object[] {r1, r2, r3, r4, r5, r6})),
- new object[] {42, "abc", 24.0f, 10d, "123", 24});
+ (r1, r2, r3, r4, r5, r6) => tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6 })),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24 });
+ }
+
+ [Fact]
+ public async Task OnT6Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3, r4, r5, r6) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24 });
}
[Fact]
@@ -79,8 +170,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3, r4, r5, r6, r7) => tcs.SetResult(new object[] {r1, r2, r3, r4, r5, r6, r7})),
- new object[] {42, "abc", 24.0f, 10d, "123", 24, 'c'});
+ (r1, r2, r3, r4, r5, r6, r7) => tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6, r7 })),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24, 'c' });
+ }
+
+ [Fact]
+ public async Task OnT7Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3, r4, r5, r6, r7) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6, r7 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24, 'c' });
}
[Fact]
@@ -88,8 +192,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await InvokeOn(
(hubConnection, tcs) => hubConnection.On("Foo",
- (r1, r2, r3, r4, r5, r6, r7, r8) => tcs.SetResult(new object[] {r1, r2, r3, r4, r5, r6, r7, r8})),
- new object[] {42, "abc", 24.0f, 10d, "123", 24, 'c', "XYZ"});
+ (r1, r2, r3, r4, r5, r6, r7, r8) => tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6, r7, r8 })),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24, 'c', "XYZ" });
+ }
+
+ [Fact]
+ public async Task OnT8Async()
+ {
+ await InvokeOn(
+ (hubConnection, tcs) => hubConnection.On("Foo",
+ (r1, r2, r3, r4, r5, r6, r7, r8) =>
+ {
+ tcs.SetResult(new object[] { r1, r2, r3, r4, r5, r6, r7, r8 });
+ return Task.CompletedTask;
+ }),
+ new object[] { 42, "abc", 24.0f, 10d, "123", 24, 'c', "XYZ" });
}
private async Task InvokeOn(Action> onAction, object[] args)
@@ -137,7 +254,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
invocationId = "1",
type = 1,
target = "Foo",
- arguments = new object[] {42, "42"}
+ arguments = new object[] { 42, "42" }
}).OrTimeout();
await connection.ReceiveJsonMessage(
@@ -146,7 +263,49 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
invocationId = "2",
type = 1,
target = "Foo",
- arguments = new object[] {42}
+ arguments = new object[] { 42 }
+ }).OrTimeout();
+
+ Assert.Equal(42, await receiveTcs.Task.OrTimeout());
+ }
+ finally
+ {
+ await hubConnection.DisposeAsync().OrTimeout();
+ }
+ }
+
+ [Fact]
+ public async Task ConnectionNotClosedOnAsyncCallbackArgumentCountMismatch()
+ {
+ var connection = new TestConnection();
+ var hubConnection = CreateHubConnection(connection);
+ var receiveTcs = new TaskCompletionSource();
+
+ try
+ {
+ hubConnection.On("Foo", r =>
+ {
+ receiveTcs.SetResult(r);
+ return Task.CompletedTask;
+ });
+ await hubConnection.StartAsync().OrTimeout();
+
+ await connection.ReceiveJsonMessage(
+ new
+ {
+ invocationId = "1",
+ type = 1,
+ target = "Foo",
+ arguments = new object[] { 42, "42" }
+ }).OrTimeout();
+
+ await connection.ReceiveJsonMessage(
+ new
+ {
+ invocationId = "2",
+ type = 1,
+ target = "Foo",
+ arguments = new object[] { 42 }
}).OrTimeout();
Assert.Equal(42, await receiveTcs.Task.OrTimeout());
@@ -175,7 +334,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
invocationId = "1",
type = 1,
target = "Foo",
- arguments = new object[] {"xxx"}
+ arguments = new object[] { "xxx" }
}).OrTimeout();
await connection.ReceiveJsonMessage(
@@ -184,7 +343,49 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
invocationId = "2",
type = 1,
target = "Foo",
- arguments = new object[] {42}
+ arguments = new object[] { 42 }
+ }).OrTimeout();
+
+ Assert.Equal(42, await receiveTcs.Task.OrTimeout());
+ }
+ finally
+ {
+ await hubConnection.DisposeAsync().OrTimeout();
+ }
+ }
+
+ [Fact]
+ public async Task ConnectionNotClosedOnAsyncCallbackArgumentTypeMismatch()
+ {
+ var connection = new TestConnection();
+ var hubConnection = CreateHubConnection(connection);
+ var receiveTcs = new TaskCompletionSource();
+
+ try
+ {
+ hubConnection.On("Foo", r =>
+ {
+ receiveTcs.SetResult(r);
+ return Task.CompletedTask;
+ });
+ await hubConnection.StartAsync().OrTimeout();
+
+ await connection.ReceiveJsonMessage(
+ new
+ {
+ invocationId = "1",
+ type = 1,
+ target = "Foo",
+ arguments = new object[] { "xxx" }
+ }).OrTimeout();
+
+ await connection.ReceiveJsonMessage(
+ new
+ {
+ invocationId = "2",
+ type = 1,
+ target = "Foo",
+ arguments = new object[] { 42 }
}).OrTimeout();
Assert.Equal(42, await receiveTcs.Task.OrTimeout());