14 KiB
title | author | description | monikerRange | ms.author | ms.custom | ms.date | uid |
---|---|---|---|---|---|---|---|
ASP.NET Core SignalR JavaScript client | bradygaster | Overview of ASP.NET Core SignalR JavaScript client. | >= aspnetcore-2.1 | bradyg | mvc | 04/17/2019 | signalr/javascript-client |
ASP.NET Core SignalR JavaScript client
By Rachel Appel
The ASP.NET Core SignalR JavaScript client library enables developers to call server-side hub code.
View or download sample code (how to download)
Install the SignalR client package
The SignalR JavaScript client library is delivered as an npm package. If you're using Visual Studio, run npm install
from the Package Manager Console while in the root folder. For Visual Studio Code, run the command from the Integrated Terminal.
npm init -y
npm install @aspnet/signalr
npm installs the package contents in the node_modules\@aspnet\signalr\dist\browser folder. Create a new folder named signalr under the wwwroot\lib folder. Copy the signalr.js file to the wwwroot\lib\signalr folder.
Use the SignalR JavaScript client
Reference the SignalR JavaScript client in the <script>
element.
<script src="~/lib/signalr/signalr.js"></script>
Connect to a hub
The following code creates and starts a connection. The hub's name is case insensitive.
[!code-javascriptCall hub methods]
Cross-origin connections
Typically, browsers load connections from the same domain as the requested page. However, there are occasions when a connection to another domain is required.
To prevent a malicious site from reading sensitive data from another site, cross-origin connections are disabled by default. To allow a cross-origin request, enable it in the Startup
class.
[!code-csharpCross-origin connections]
Call hub methods from client
JavaScript clients call public methods on hubs via the invoke method of the HubConnection. The invoke
method accepts two arguments:
-
The name of the hub method. In the following example, the method name on the hub is
SendMessage
. -
Any arguments defined in the hub method. In the following example, the argument name is
message
. The example code uses arrow function syntax that is supported in current versions of all major browsers except Internet Explorer.[!code-javascriptCall hub methods]
[!NOTE] If you're using Azure SignalR Service in Serverless mode, you cannot call hub methods from a client. For more information, see the SignalR Service documentation.
The invoke
method returns a JavaScript Promise. The Promise
is resolved with the return value (if any) when the method on the server returns. If the method on the server throws an error, the Promise
is rejected with the error message. Use the then
and catch
methods on the Promise
itself to handle these cases (or await
syntax).
The send
method returns a JavaScript Promise
. The Promise
is resolved when the message has been sent to the server. If there is an error sending the message, the Promise
is rejected with the error message. Use the then
and catch
methods on the Promise
itself to handle these cases (or await
syntax).
[!NOTE] Using
send
doesn't wait until the server has received the message. Consequently, it's not possible to return data or errors from the server.
Call client methods from hub
To receive messages from the hub, define a method using the on method of the HubConnection
.
- The name of the JavaScript client method. In the following example, the method name is
ReceiveMessage
. - Arguments the hub passes to the method. In the following example, the argument value is
message
.
[!code-javascriptReceive calls from hub]
The preceding code in connection.on
runs when server-side code calls it using the SendAsync method.
[!code-csharpCall client-side]
SignalR determines which client method to call by matching the method name and arguments defined in SendAsync
and connection.on
.
[!NOTE] As a best practice, call the start method on the
HubConnection
afteron
. Doing so ensures your handlers are registered before any messages are received.
Error handling and logging
Chain a catch
method to the end of the start
method to handle client-side errors. Use console.error
to output errors to the browser's console.
[!code-javascriptError handling]
Setup client-side log tracing by passing a logger and type of event to log when the connection is made. Messages are logged with the specified log level and higher. Available log levels are as follows:
signalR.LogLevel.Error
– Error messages. LogsError
messages only.signalR.LogLevel.Warning
– Warning messages about potential errors. LogsWarning
, andError
messages.signalR.LogLevel.Information
– Status messages without errors. LogsInformation
,Warning
, andError
messages.signalR.LogLevel.Trace
– Trace messages. Logs everything, including data transported between hub and client.
Use the configureLogging method on HubConnectionBuilder to configure the log level. Messages are logged to the browser console.
[!code-javascriptLogging levels]
Reconnect clients
::: moniker range=">= aspnetcore-3.0"
Automatically reconnect
The JavaScript client for SignalR can be configured to automatically reconnect using the withAutomaticReconnect
method on HubConnectionBuilder. It won't automatically reconnect by default.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.withAutomaticReconnect()
.build();
Without any parameters, withAutomaticReconnect()
configures the client to wait 0, 2, 10, and 30 seconds respectively before trying each reconnect attempt, stopping after four failed attempts.
Before starting any reconnect attempts, the HubConnection
will transition to the HubConnectionState.Reconnecting
state and fire its onreconnecting
callbacks instead of transitioning to the Disconnected
state and triggering its onclose
callbacks like a HubConnection
without automatic reconnect configured. This provides an opportunity to warn users that the connection has been lost and to disable UI elements.
connection.onreconnecting((error) => {
console.assert(connection.state === signalR.HubConnectionState.Reconnecting);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection lost due to error "${error}". Reconnecting.`;
document.getElementById("messagesList").appendChild(li);
});
If the client successfully reconnects within its first four attempts, the HubConnection
will transition back to the Connected
state and fire its onreconnected
callbacks. This provides an opportunity to inform users the connection has been reestablished.
Since the connection looks entirely new to the server, a new connectionId
will be provided to the onreconnected
callback.
[!WARNING] The
onreconnected
callback'sconnectionId
parameter will be undefined if theHubConnection
was configured to skip negotiation.
connection.onreconnected((connectionId) => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
document.getElementById("messageInput").disabled = false;
const li = document.createElement("li");
li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
document.getElementById("messagesList").appendChild(li);
});
withAutomaticReconnect()
won't configure the HubConnection
to retry initial start failures, so start failures need to be handled manually:
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("connected");
} catch (err) {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
console.log(err);
setTimeout(() => start(), 5000);
}
};
If the client doesn't successfully reconnect within its first four attempts, the HubConnection
will transition to the Disconnected
state and fire its onclose callbacks. This provides an opportunity to inform users the connection has been permanently lost and recommend refreshing the page:
connection.onclose((error) => {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
document.getElementById("messagesList").appendChild(li);
})
In order to configure a custom number of reconnect attempts before disconnecting or change the reconnect timing, withAutomaticReconnect
accepts an array of numbers representing the delay in milliseconds to wait before starting each reconnect attempt.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
The preceding example configures the HubConnection
to start attempting reconnects immediately after the connection is lost. This is also true for the default configuration.
If the first reconnect attempt fails, the second reconnect attempt will also start immediately instead of waiting 2 seconds like it would in the default configuration.
If the second reconnect attempt fails, the third reconnect attempt will start in 10 seconds which is again like the default configuration.
The custom behavior then diverges again from the default behavior by stopping after the third reconnect attempt failure instead of trying one more reconnect attempt in another 30 seconds like it would in the default configuration.
If you want even more control over the timing and number of automatic reconnect attempts, withAutomaticReconnect
accepts an object implementing the IReconnectPolicy
interface, which has a single method named nextRetryDelayInMilliseconds
.
nextRetryDelayInMilliseconds
takes two arguments, previousRetryCount
and elapsedMilliseconds
, which are both numbers. Before the first reconnect attempt, both previousRetryCount
and elapsedMilliseconds
will be zero. After each failed retry attempt, previousRetryCount
will be incremented by one and elapsedMilliseconds
will be updated to reflect the amount of time spent reconnecting so far in milliseconds.
nextRetryDelayInMilliseconds
must return either a number representing the number of milliseconds to wait before the next reconnect attempt or null
if the HubConnection
should stop reconnecting.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: (previousRetryCount, elapsedMilliseconds) => {
if (elapsedMilliseconds < 60000) {
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
})
.build();
Alternatively, you can write code that will reconnect your client manually as demonstrated in Manually reconnect.
::: moniker-end
Manually reconnect
::: moniker range="< aspnetcore-3.0"
[!WARNING] Prior to 3.0, the JavaScript client for SignalR doesn't automatically reconnect. You must write code that will reconnect your client manually.
::: moniker-end
The following code demonstrates a typical manual reconnection approach:
- A function (in this case, the
start
function) is created to start the connection. - Call the
start
function in the connection'sonclose
event handler.
[!code-javascriptReconnect the JavaScript client]
A real-world implementation would use an exponential back-off or retry a specified number of times before giving up.