From 1ce208efea8f832619f26986a8ffb0cad0709f57 Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Wed, 4 May 2022 09:02:11 -0700 Subject: [PATCH 1/6] [SignalR] Document client results --- aspnetcore/signalr/client-features.md | 1 + aspnetcore/signalr/hubs.md | 73 +++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/aspnetcore/signalr/client-features.md b/aspnetcore/signalr/client-features.md index 6fbcbca909d9..2044c118aa3b 100644 --- a/aspnetcore/signalr/client-features.md +++ b/aspnetcore/signalr/client-features.md @@ -41,6 +41,7 @@ The table below shows the features and support for the clients that offer real-t | Long Polling Transport |2.1.0|1.0.0|1.0.0|3.0.0| | JSON Hub Protocol |2.1.0|1.0.0|1.0.0|1.0.0| | MessagePack Hub Protocol |2.1.0|1.0.0|1.0.0|5.0.0| +| Client Results |7.0.0|7.0.0|7.0.0|❌| Support for enabling additional client features is tracked in [our issue tracker](https://github.com/dotnet/AspNetCore/issues). diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index acc61ad515f7..b572a50e8e95 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -577,11 +577,14 @@ The class includes a | Calls a method on all connections in the specified group, except the specified connections | | | Calls a method on multiple groups of connections | | | Calls a method on a group of connections, excluding the client that invoked the hub method | +| | calls a method on a specific connected client | | | Calls a method on all connections associated with a specific user | | | Calls a method on all connections associated with the specified users | Each property or method in the preceding tables returns an object with a `SendAsync` method. The `SendAsync` method receives the name of the client method to call and any parameters. +The object returned by the `Single` method also contains an `InvokeAsync` method which can be used to wait for a [result from the client](xref:signalr/hubs#client-results). + ## Send messages to clients To make calls to specific clients, use the properties of the `Clients` object. In the following example, there are three hub methods: @@ -609,6 +612,76 @@ Using `Hub` enables compile-time checking of the client methods. Th > [!NOTE] > The `Async` suffix isn't stripped from method names. Unless a client method is defined with `.on('MyMethodAsync')`, don't use `MyMethodAsync` as the name. +## Client results + +In addition to making calls to clients, the server can request a result from the client. This requires the server to use `ISingleClientProxy.InvokeAsync` and the client to return a result from their `.On` handler. + +There are two ways to use the API on the server, the first is to call `Single(...)` on the `Clients` property in a Hub method. +```csharp +public class ChatHub : Hub +{ + public async Task WaitForMessage(string connectionId) + { + var message = await Clients.Single(connectionId).InvokeAsync("GetMessage"); + return message; + } +} +``` + +> [!NOTE] +> Currently using `InvokeAsync` from a Hub method requires setting the [MaximumParallelInvocationsPerClient](xref:signalr/configuration#configure-server-options) option to a value greater than 1. + +The second way is to call `Single(...)` on an instance of [IHubContext](xref:signalr/hubcontext). +```csharp +async Task SomeMethod(IHubContext context) +{ + string result = await context.Single(connectionID).InvokeAsync("GetMessage"); +} +``` + +Strongly-typed hubs can also return values from interface methods: +```csharp +public interface IClient +{ + Task GetMessage(); +} + +public class ChatHub : Hub +{ + public async Task WaitForMessage(string connectionId) + { + string message = await Clients.Single(connectionId).GetMessage(); + return message; + } +} +``` + +Clients return results in their `.On(...)` handlers as shown below: + +### .NET client +```csharp +hubConnection.On("GetMessage", async () => +{ + Console.WriteLine("Enter message:"); + var message = await Console.In.ReadLineAsync(); + return message; +}); +``` +### Typescript client +```typescript +hubConnection.on("GetMessage", async () => { + let promise = new Promise((resolve, reject) => { + setTimeout(() => { + resolve("message"); + }, 100); + }); + return promise; +}); +``` + +> [!NOTE] +> Client results does not work with the Azure SignalR Service currently. + ## Change the name of a hub method By default, a server hub method name is the name of the .NET method. To change this default behavior for a specific method, use the [HubMethodName](xref:Microsoft.AspNetCore.SignalR.HubMethodNameAttribute) attribute. The client should use this name instead of the .NET method name when invoking the method: From 3579b7ef8cb03dfb5870674cf917a69f73545d43 Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Wed, 4 May 2022 09:21:16 -0700 Subject: [PATCH 2/6] nits --- aspnetcore/signalr/hubs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index b572a50e8e95..45c20e4444d5 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -631,7 +631,7 @@ public class ChatHub : Hub > [!NOTE] > Currently using `InvokeAsync` from a Hub method requires setting the [MaximumParallelInvocationsPerClient](xref:signalr/configuration#configure-server-options) option to a value greater than 1. -The second way is to call `Single(...)` on an instance of [IHubContext](xref:signalr/hubcontext). +The second way is to call `Single(...)` on an instance of [`IHubContext`](xref:signalr/hubcontext). ```csharp async Task SomeMethod(IHubContext context) { @@ -658,7 +658,7 @@ public class ChatHub : Hub Clients return results in their `.On(...)` handlers as shown below: -### .NET client +#### .NET client ```csharp hubConnection.On("GetMessage", async () => { @@ -667,7 +667,7 @@ hubConnection.On("GetMessage", async () => return message; }); ``` -### Typescript client +#### Typescript client ```typescript hubConnection.on("GetMessage", async () => { let promise = new Promise((resolve, reject) => { @@ -680,7 +680,7 @@ hubConnection.on("GetMessage", async () => { ``` > [!NOTE] -> Client results does not work with the Azure SignalR Service currently. +> Client results do not work with the Azure SignalR Service currently. ## Change the name of a hub method From 5eb070d204d98c167de71fe1e260efb218438b9b Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Wed, 4 May 2022 14:11:41 -0700 Subject: [PATCH 3/6] no xref --- aspnetcore/signalr/hubs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index 45c20e4444d5..3f88cc8944a9 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -577,7 +577,7 @@ The class includes a | Calls a method on all connections in the specified group, except the specified connections | | | Calls a method on multiple groups of connections | | | Calls a method on a group of connections, excluding the client that invoked the hub method | -| | calls a method on a specific connected client | +| Single | calls a method on a specific connected client | | | Calls a method on all connections associated with a specific user | | | Calls a method on all connections associated with the specified users | From bed4a7a8d2095fcf390ded1683b5239a6a9e54f6 Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Wed, 4 May 2022 16:03:20 -0700 Subject: [PATCH 4/6] fb --- aspnetcore/signalr/hubs.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index 3f88cc8944a9..52d3b2043044 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -577,13 +577,13 @@ The class includes a | Calls a method on all connections in the specified group, except the specified connections | | | Calls a method on multiple groups of connections | | | Calls a method on a group of connections, excluding the client that invoked the hub method | -| Single | calls a method on a specific connected client | +| `Single` | Calls a method on a specific connected client | | | Calls a method on all connections associated with a specific user | | | Calls a method on all connections associated with the specified users | Each property or method in the preceding tables returns an object with a `SendAsync` method. The `SendAsync` method receives the name of the client method to call and any parameters. -The object returned by the `Single` method also contains an `InvokeAsync` method which can be used to wait for a [result from the client](xref:signalr/hubs#client-results). +The object returned by the `Single` method also contains an `InvokeAsync` method, which can be used to wait for a [result from the client](xref:signalr/hubs#client-results). ## Send messages to clients @@ -614,32 +614,38 @@ Using `Hub` enables compile-time checking of the client methods. Th ## Client results -In addition to making calls to clients, the server can request a result from the client. This requires the server to use `ISingleClientProxy.InvokeAsync` and the client to return a result from their `.On` handler. +In addition to making calls to clients, the server can request a result from a client. This requires the server to use `ISingleClientProxy.InvokeAsync` and the client to return a result from their `.On` handler. + +There are two ways to use the API on the server, the first is to call `Single(...)` on the `Clients` property in a Hub method: -There are two ways to use the API on the server, the first is to call `Single(...)` on the `Clients` property in a Hub method. ```csharp public class ChatHub : Hub { public async Task WaitForMessage(string connectionId) { - var message = await Clients.Single(connectionId).InvokeAsync("GetMessage"); + var message = await Clients.Single(connectionId).InvokeAsync( + "GetMessage"); return message; } } ``` > [!NOTE] -> Currently using `InvokeAsync` from a Hub method requires setting the [MaximumParallelInvocationsPerClient](xref:signalr/configuration#configure-server-options) option to a value greater than 1. +> Using `InvokeAsync` from a Hub method requires setting the [`MaximumParallelInvocationsPerClient`](xref:signalr/configuration#configure-server-options) option to a value greater than 1. +> This will be addressed in a future release. For more information, see [Support returning values from client invocations](https://github.com/dotnet/aspnetcore/issues/5280). + +The second way is to call `Single(...)` on an instance of [`IHubContext`](xref:signalr/hubcontext): -The second way is to call `Single(...)` on an instance of [`IHubContext`](xref:signalr/hubcontext). ```csharp async Task SomeMethod(IHubContext context) { - string result = await context.Single(connectionID).InvokeAsync("GetMessage"); + string result = await context.Single(connectionID).InvokeAsync( + "GetMessage"); } ``` Strongly-typed hubs can also return values from interface methods: + ```csharp public interface IClient { @@ -656,9 +662,10 @@ public class ChatHub : Hub } ``` -Clients return results in their `.On(...)` handlers as shown below: +Clients return results in their `.On(...)` handlers, as shown below: #### .NET client + ```csharp hubConnection.On("GetMessage", async () => { @@ -667,7 +674,9 @@ hubConnection.On("GetMessage", async () => return message; }); ``` + #### Typescript client + ```typescript hubConnection.on("GetMessage", async () => { let promise = new Promise((resolve, reject) => { @@ -680,7 +689,8 @@ hubConnection.on("GetMessage", async () => { ``` > [!NOTE] -> Client results do not work with the Azure SignalR Service currently. +> Client results don't work with the Azure SignalR Service. +> This will be addressed in a future release. For more information, see [Support returning values from client invocations](https://github.com/dotnet/aspnetcore/issues/5280). ## Change the name of a hub method From 62916344e2acde53ce7aa60eb30309b8bca499e1 Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 4 May 2022 17:06:50 -0700 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com> --- aspnetcore/signalr/hubs.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index 52d3b2043044..26590ff774d7 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -614,7 +614,7 @@ Using `Hub` enables compile-time checking of the client methods. Th ## Client results -In addition to making calls to clients, the server can request a result from a client. This requires the server to use `ISingleClientProxy.InvokeAsync` and the client to return a result from their `.On` handler. +In addition to making calls to clients, the server can request a result from a client. This requires the server to use `ISingleClientProxy.InvokeAsync` and the client to return a result from its `.On` handler. There are two ways to use the API on the server, the first is to call `Single(...)` on the `Clients` property in a Hub method: @@ -632,6 +632,7 @@ public class ChatHub : Hub > [!NOTE] > Using `InvokeAsync` from a Hub method requires setting the [`MaximumParallelInvocationsPerClient`](xref:signalr/configuration#configure-server-options) option to a value greater than 1. +> > This will be addressed in a future release. For more information, see [Support returning values from client invocations](https://github.com/dotnet/aspnetcore/issues/5280). The second way is to call `Single(...)` on an instance of [`IHubContext`](xref:signalr/hubcontext): @@ -690,6 +691,7 @@ hubConnection.on("GetMessage", async () => { > [!NOTE] > Client results don't work with the Azure SignalR Service. +> > This will be addressed in a future release. For more information, see [Support returning values from client invocations](https://github.com/dotnet/aspnetcore/issues/5280). ## Change the name of a hub method From 70d7189ea9238798cb7261952af182025300bf5d Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 10 May 2022 08:50:57 -0700 Subject: [PATCH 6/6] Apply suggestions from code review --- aspnetcore/signalr/hubs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/signalr/hubs.md b/aspnetcore/signalr/hubs.md index 26590ff774d7..a17126941587 100644 --- a/aspnetcore/signalr/hubs.md +++ b/aspnetcore/signalr/hubs.md @@ -640,7 +640,7 @@ The second way is to call `Single(...)` on an instance of [`IHubContext`](xre ```csharp async Task SomeMethod(IHubContext context) { - string result = await context.Single(connectionID).InvokeAsync( + string result = await context.Clients.Single(connectionID).InvokeAsync( "GetMessage"); } ```