Add support for Async On Delegates (#7700)

This commit is contained in:
Mikael Mengistu 2019-02-20 15:44:54 -08:00 committed by GitHub
parent e1d506e961
commit f33cc20dbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 426 additions and 20 deletions

View File

@ -242,5 +242,210 @@ namespace Microsoft.AspNetCore.SignalR.Client
return currentHandler(parameters);
}, handler);
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On(this HubConnection hubConnection, string methodName, Func<Task> handler)
{
if (hubConnection == null)
{
throw new ArgumentNullException(nameof(hubConnection));
}
return hubConnection.On(methodName, Type.EmptyTypes, args => handler());
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1>(this HubConnection hubConnection, string methodName, Func<T1, Task> handler)
{
if (hubConnection == null)
{
throw new ArgumentNullException(nameof(hubConnection));
}
return hubConnection.On(methodName,
new[] { typeof(T1) },
args => handler((T1)args[0]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2>(this HubConnection hubConnection, string methodName, Func<T1, T2, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <typeparam name="T4">The fourth argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3, T4>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, T4, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <typeparam name="T4">The fourth argument type.</typeparam>
/// <typeparam name="T5">The fifth argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3, T4, T5>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, T4, T5, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <typeparam name="T4">The fourth argument type.</typeparam>
/// <typeparam name="T5">The fifth argument type.</typeparam>
/// <typeparam name="T6">The sixth argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3, T4, T5, T6>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, T4, T5, T6, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <typeparam name="T4">The fourth argument type.</typeparam>
/// <typeparam name="T5">The fifth argument type.</typeparam>
/// <typeparam name="T6">The sixth argument type.</typeparam>
/// <typeparam name="T7">The seventh argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3, T4, T5, T6, T7>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, T4, T5, T6, T7, Task> 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]));
}
/// <summary>
/// Registers a handler that will be invoked when the hub method with the specified method name is invoked.
/// </summary>
/// <typeparam name="T1">The first argument type.</typeparam>
/// <typeparam name="T2">The second argument type.</typeparam>
/// <typeparam name="T3">The third argument type.</typeparam>
/// <typeparam name="T4">The fourth argument type.</typeparam>
/// <typeparam name="T5">The fifth argument type.</typeparam>
/// <typeparam name="T6">The sixth argument type.</typeparam>
/// <typeparam name="T7">The seventh argument type.</typeparam>
/// <typeparam name="T8">The eighth argument type.</typeparam>
/// <param name="hubConnection">The hub connection.</param>
/// <param name="methodName">The name of the hub method to define.</param>
/// <param name="handler">The handler that will be raised when the hub method is invoked.</param>
/// <returns>A subscription that can be disposed to unsubscribe from the hub method.</returns>
public static IDisposable On<T1, T2, T3, T4, T5, T6, T7, T8>(this HubConnection hubConnection, string methodName, Func<T1, T2, T3, T4, T5, T6, T7, T8, Task> 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]));
}
}
}

View File

@ -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<int>("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<int>("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<int, string>("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<int, string>("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<int, string, float>("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<int, string, float>("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<int, string, float, double>("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<int, string, float, double>("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<int, string, float, double, string>("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<int, string, float, double, string>("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<int, string, float, double, string, byte>("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<int, string, float, double, string, byte>("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<int, string, float, double, string, byte, char>("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<int, string, float, double, string, byte, char>("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<int, string, float, double, string, byte, char, string>("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<int, string, float, double, string, byte, char, string>("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<HubConnection, TaskCompletionSource<object[]>> 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<int>();
try
{
hubConnection.On<int>("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<int>();
try
{
hubConnection.On<int>("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());