You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
title: Client negotiation in Azure SignalR service
3
-
description: This article provides information about client negotiation in Azure SignalR service.
2
+
title: Client negotiation in Azure SignalR Service
3
+
description: This article provides information about client negotiation in Azure SignalR Service.
4
4
author: JialinXin
5
5
ms.author: jixin
6
6
ms.service: signalr
@@ -10,104 +10,104 @@ ms.date: 12/08/2023
10
10
11
11
# Client negotiation
12
12
13
-
The first request between client and server is the negotiation request. When use self-host SignalR, the request is used to establish a connection between the client and the server. And when use Azure SignalR service, clients connect to the service instead of the application server. This article shares the concept about negotiation protocols and ways to customize negotiation endpoint.
13
+
The first request between a client and a server is the negotiation request. When you use self-hosted SignalR, you use the request to establish a connection between the client and the server. And when you use Azure SignalR Service, clients connect to the service instead of the application server. This article shares concepts about negotiation protocols and ways to customize a negotiation endpoint.
14
14
15
15
## What is negotiation?
16
16
17
17
The response to the `POST [endpoint-base]/negotiate` request contains one of three types of responses:
18
18
19
-
* A response that contains the `connectionId`, which is used to identify the connection on the server and the list of the transports supported by the server.
19
+
* A response that contains `connectionId`, which identifies the connection on the server and the list of transports that the server supports:
The payload returned from this endpoint provides the following data:
42
+
The payload that this endpoint returns provides the following data:
43
43
44
-
* The `connectionId` is **required** by the Long Polling and Server-Sent Events transports (in order to correlate sends and receives).
45
-
* The `negotiateVersion` is the negotiation protocol version being used between the server and client.
46
-
* The `availableTransports` list describes the transports the server supports. For each transport, the name of the transport (`transport`) is listed, as is a list of "transfer formats" supported by the transport (`transferFormats`)
44
+
* The `connectionId`value is required by the `LongPolling`and `ServerSentEvents`transports to correlate sending and receiving.
45
+
* The `negotiateVersion`value is the negotiation protocol version that you use between the server and the client.
46
+
* The `availableTransports` list describes the transports that the server supports. For each transport, the payload lists the name of the transport (`transport`) and a list of transfer formats that the transport supports (`transferFormats`).
47
47
48
-
> [!NOTE]
49
-
> Now Azure SignalR service supports negotiate`Version 0`only. And client with the `negotiateVersion` greater than zero will get a response with `negotiateVersion=0` by design. Please check [TransportProtocols](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) for protocol details.
48
+
> [!NOTE]
49
+
> Azure SignalR Service supports only`Version 0`for the negotiation protocol. A client that has a `negotiateVersion`value greater than zero will get a response with `negotiateVersion=0` by design. For protocol details, see [Transport Protocols](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md).
50
50
51
-
* A redirect response tells the client the URL and optionally access token to use as a result.
51
+
* A redirect response that tells the client which URL and (optionally) access token to use as a result:
52
52
53
-
```json
54
-
{
55
-
"url": "https://<Server endpoint>/<Hub name>",
56
-
"accessToken": "<accessToken>"
57
-
}
58
-
```
53
+
```json
54
+
{
55
+
"url": "https://<Server endpoint>/<Hub name>",
56
+
"accessToken": "<accessToken>"
57
+
}
58
+
```
59
59
60
-
The payload returned from this endpoint provides the following data:
61
-
62
-
* The `url` is the URL the client should connect to.
63
-
* The `accessToken` is an optional bearer token for accessing the specified url.
60
+
The payload that this endpoint returns provides the following data:
64
61
65
-
* A response that contains an `error` that should stop the connection attempt.
62
+
* The `url` value is the URL that the client should connect to.
63
+
* The `accessToken` value is an optional bearer token for accessing the specified URL.
66
64
67
-
```json
68
-
{
69
-
"error": "This connection is not allowed."
70
-
}
71
-
```
65
+
* A response that contains an `error` entry that should stop the connection attempt:
72
66
73
-
The payload returned from this endpoint provides the following data:
67
+
```json
68
+
{
69
+
"error": "This connection is not allowed."
70
+
}
71
+
```
74
72
75
-
*The `error` that gives details about why the negotiation failed.
73
+
The payload that this endpoint returns provides the following data:
76
74
77
-
When you use the Azure SignalR service, clients connect to the service instead of the application server. There are three steps to establish persistent connections between the client and the SignalR Service.
75
+
* The `error` string gives details about why the negotiation failed.
78
76
79
-
1. A client sends a negotiate request to the application server.
77
+
When you use Azure SignalR Service, clients connect to the service instead of the app server. There are three steps to establish persistent connections between the client and Azure SignalR Service:
80
78
81
-
1.The application server uses Azure SignalR Service SDK to return a redirect response containing the Azure SignalR service URL and access token.
79
+
1.A client sends a negotiation request to the app server.
82
80
83
-
For ASP.NET Core SignalR, a typical redirect response looks like:
81
+
1. The app server uses the Azure SignalR Service SDK to return a redirect response that contains the Azure SignalR Service URL and access token.
1. After the client receives the redirect response, it uses the URL and access token to connect to SignalR Service. The service then routes the client to the app server.
93
93
94
94
> [!IMPORTANT]
95
-
>Inself-hostSignalR, someuserwouldchoosetoskipclientnegotiationwhenclientsonlysupportWebSocketandsavetheroundtripfor negotiation. However, when working with Azure SignalR service, clients should always ask a trusted server or a trusted authntication center to build the access token. So __DO NOT__ set `SkipNegotiation` to `true` in client side. `SkipNegotiation` means clients need to build the accessToken themselves. This brings security risks that client could do anything to the service endpoint.
95
+
> In self-hosted SignalR, some users might choose to skip client negotiation when clients support only WebSocket and save the round trip for negotiation. However, when you're working with Azure SignalR Service, clients should always ask a trusted server or a trusted authentication center to build the access token. So _don't_set `SkipNegotiation` to `true`on the client side. `SkipNegotiation` means clients need to build the access token themselves. This setting brings a security risk that the client could do anything to the service endpoint.
96
96
97
-
## What can be done during negotiation?
97
+
## What can you do during negotiation?
98
98
99
99
### Custom settings for client connections
100
100
101
-
Customer can gate the client connection to customize settings for security or business needs. For example:
101
+
You can gate the client connection to customize settings for security or business needs. For example:
102
102
103
-
* Use a short `AccessTokenLifetime` for security
104
-
* Only pass necessary info of client claims
105
-
* Add custom claims for business needs
103
+
* Use a short `AccessTokenLifetime`value for security.
104
+
*Pass only necessary information from client claims.
105
+
* Add custom claims for business needs.
106
106
107
107
```cs
108
108
services.AddSignalR().AddAzureSignalR(options=>
109
109
{
110
-
//Only pass necessary info in negotiation step
110
+
//Pass only necessary information in the negotiation step
When you have multiple app servers, by default there's no guarantee that two servers (the one who does negotiation and the one who gets the hub invocation) are the same one. In some cases, customers may want to have client state information maintained locally on the app server. For example, when using server-side Blazor, UI state is maintained at server side so you want all client requests go to the same server including the SignalR connection. Then you would need to enable server sticky mode to `Required` during negotiation.
122
+
When you have multiple app servers, there's no guarantee (by default) that the server that does negotiation and the server that gets the hub invocation are the same. In some cases, you might want to have client state information maintained locally on the app server.
123
+
124
+
For example, when you're using server-side Blazor, the UI state is maintained at the server side. So you want all client requests to go to the same server, including the SignalR connection. Then you need to enable server sticky mode to `Required` during negotiation:
Another case customer would customize negotiation is in multiple endpoints cases. Since app server provides the service URL as the negotiation response, app server can determine which endpoint to return clients for load balancing and communication efficiency, that islet client connect to the nearest service endpoint to save traffic cost.
134
+
Another way that you can customize negotiation is in multiple endpoints. Because the app server provides the service URL as the negotiation response, the app server can determine which endpoint to return to clients for load balancing and communication efficiency. That is, you can let the client connect to the nearest service endpoint to save traffic costs.
@@ -147,15 +149,16 @@ private class CustomRouter : EndpointRouterDecorator
147
149
returnnull;
148
150
}
149
151
150
-
returnendpoints.FirstOrDefault(s=>s.Name==endpointName&&s.Online) // Get the endpoint with name matching the incoming request
151
-
??base.GetNegotiateEndpoint(context, endpoints); //Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
152
+
returnendpoints.FirstOrDefault(s=>s.Name==endpointName&&s.Online) // Get the endpoint with the name that matches the incoming request
153
+
??base.GetNegotiateEndpoint(context, endpoints); //Fall back to the default behavior to randomly select one from primary endpoints, or fall back to secondary when no primary ones are online
152
154
}
153
155
}
154
156
```
155
157
156
-
Besides, also register the router to DI using:
158
+
Also register the router to dependency injection:
159
+
157
160
```cs
158
-
// Sample of configure multiple endpoints and DI CustomRouter.
161
+
// Sample of configuring multiple endpoints and dependency injection
## How to add a client negotiation endpoint in `Serverless` mode?
176
+
## How can you add a client negotiation endpoint in serverless mode?
174
177
175
-
Under `Serverless` mode, there's is no server accepts SignalR clients. To protect your connection string, you need to redirect SignalR clients from the negotiation endpoint to Azure SignalR Service instead of giving your connection string to all the SignalR clients.
178
+
In serverless (`Serverless`) mode, no server accepts SignalR clients. To help protect your connection string, you need to redirect SignalR clients from the negotiation endpoint to Azure SignalR Service instead of giving your connection string to all the SignalR clients.
176
179
177
-
The best practice is to host a negotiation endpoint and then you can use SignalR clients to this endpoint and fetch service url and access token.
180
+
The best practice is to host a negotiation endpoint. Then you can use SignalR clients to this endpoint and fetch the service URL and access token.
178
181
179
-
### Azure SignalR service Management SDK
182
+
### Azure SignalR Service Management SDK
180
183
181
-
Negotiation can be approached by working with [Management SDK](https://github.com/Azure/azure-signalr/blob/dev/docs/management-sdk-guide.md).
184
+
You can approach negotiation by working with the[Management SDK](https://github.com/Azure/azure-signalr/blob/dev/docs/management-sdk-guide.md).
182
185
183
-
You can use the instance of `ServiceHubContext` to generate the endpoint url and corresponding access token for SignalR clients to connect to your Azure SignalR Service.
186
+
You can use the instance of `ServiceHubContext` to generate the endpoint URL and corresponding access token for SignalR clients to connect to Azure SignalR Service:
184
187
185
188
```cs
186
189
varnegotiationResponse=awaitserviceHubContext.NegotiateAsync(new (){ UserId="<Your User Id>" });
187
190
```
188
191
189
-
Suppose your hub endpoint is `http://<Your Host Name>/<Your Hub Name>`, then your negotiation endpoint is `http://<Your Host Name>/<Your Hub Name>/negotiate`. Once you host the negotiation endpoint, you can use the SignalR clients to connect to your hub like this:
192
+
Suppose your hub endpoint is `http://<Your Host Name>/<Your Hub Name>`. Then your negotiation endpoint is `http://<Your Host Name>/<Your Hub Name>/negotiate`. After you host the negotiation endpoint, you can use the SignalR clients to connect to your hub:
A full sample on how to use Management SDK to redirect SignalR clients to Azure SignalR Service can be found [here](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/Management).
199
+
You can find a full sample on how to use the Management SDK to redirect SignalR clients to Azure SignalR Service on [GitHub](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/Management).
197
200
198
-
### Azure SignalR service functions extension
201
+
### Azure SignalR Service function extension
199
202
200
-
When you use Azure Function App, typically, you can work with the Function Extension. Here's a sample using `SignalRConnectionInfo` to help you build the negotiation response.
203
+
When you use an Azure function app, you can work with the function extension. Here's a sample of using `SignalRConnectionInfo` to help you build the negotiation response:
201
204
202
205
```cs
203
206
[FunctionName("negotiate")]
@@ -211,12 +214,11 @@ public SignalRConnectionInfo Negotiate([HttpTrigger(AuthorizationLevel.Anonymous
211
214
}
212
215
```
213
216
214
-
Then your clients can request to this function endpoint `https://<Your Function App Name>.azurewebsites.net/api/negotiate` to get the service url and accessToken. A full sample can be found [here](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/BidirectionChat).
217
+
Then your clients can request the function endpoint `https://<Your Function App Name>.azurewebsites.net/api/negotiate` to get the service URL and access token. You can find a full sample on [GitHub](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/BidirectionChat).
215
218
216
219
## Next steps
217
220
218
-
See the following articles to learn more about how to use Default and Serverless modes.
219
-
220
-
-[Azure SignalR Service internals](signalr-concept-internals.md)
221
+
To learn more about how to use default and serverless modes, see the following articles:
221
222
222
-
-[Azure Functions development and configuration with Azure SignalR Service](signalr-concept-serverless-development-config.md)
223
+
*[Azure SignalR Service internals](signalr-concept-internals.md)
224
+
*[Azure Functions development and configuration with Azure SignalR Service](signalr-concept-serverless-development-config.md)
0 commit comments