Resolution for common SignalR JavaScript client error websocket not in Open state elucidated through debugging and code placement adjustment.
Introduction
It's quite a common issue to face a thrown error by SignalR JavaScript client "websocket is not in the Open state". Although it may be due to different reasons, one of them is described here.
Background
Researching on the internet for hours and chatting with ChatGPT didn't end up with a solution for my scenario. Finally, I resolved the problem by lots of analyzing, debugging, creating prototype projects, etc. So here is one of the reasons of "websocket is not in the Open state" error message.
Using the Code
Usually, you have the following code in JavaScript side of the Razor pages to implement SignalR client:
<script src="~/js/signalr/dist/browser/signalr.js"></script>
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
The connection.start()
method throws that "...websocket is not in the Open state".
There is nothing wrong with the code itself, it's just the wrong spot it is placed on. Usually, developers place it inside the razor page's @section Scripts {}
block, where the whole JavaScript section goes to. Razor and MVC Frameworks, especially when dealing with complex applications with multiple scripts and libraries, load numerous libraries or scripts which are potential conflicts for the SignalR.
So placing JavaScript code inside a <script>
block within the <head>
section or at the end of the <body>
section of your HTML page is typically the recommended approach to avoid interference with other scripts or libraries.
When I moved SignalR client side code outside of the @section Scripts {}, my SignalR connection was successfully established!
<script src="~/js/signalr/dist/browser/signalr.js"></script>
<script src="~/js/signalrClient.js"></script>
@section Scripts {
<script>
...........
</script>
}
where signalrClient.js is the js code for SignalR client. Example:
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
li.textContent = `${user} says ${message}`;
});
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
Note, you can't access page Model properties via @Model.MyProperty
in signalrClient.js file as this code is outside of the framework's Section block.
That's it! Hope it helps you to save some time in dealing with SignalR implementation. Happy coding!
History
- 19th March, 2024: Initial version