I have tried many methods to detect browser close event through jQuery or JavaScript. But, unfortunately, I have not been able to detect the close. The onbeforeunload and onunload methods are also not working. How do I detect the window close using SignalR?
I want to be extremely precise, and I want to trigger an event when the user initially connected to my MVC Razor view page and I would also trigger an event when they disconnected from the page as well (through a variety of events like closing the browser, unexpected shutdowns, etc.).
this is what I tried so far:
window.onbeforeunload = function (event) {
var message = 'Important: Please click on \'Save\' button to leave this page.';
if (typeof event == 'undefined')
{
event = window.event;
}
if (event)
{
event.returnValue = message;
}
return message;
};
$(function () {
$("a").not('#lnkLogOut').click(function () {
window.onbeforeunload = null;
});
$(".btn").click(function () {
window.onbeforeunload = null;
});
});
Test Result
I am using asp.net core signalr and it also could be useful to you.
Sample code
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/mainHub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: () => {
this._errorState$.next(true);
return 1000;
},
reconnectDelay: 500 // set the reconnect delay to 500ms
})
.configureLogging(signalR.LogLevel.Debug).build();
connection.serverTimeoutInMilliseconds = 120000;
//Disable the send button until connection is established.
//document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
// We can assign user-supplied strings to an element's textContent because it
// is not interpreted as markup. If you're assigning in any other way, you
// should be aware of possible script injection concerns.
li.textContent = `${user} says ${message}`;
});
connection.start().then(function () {
console.log(connection.connectionId);
loadStatus("available");
}).catch(function (err) {
return console.error(err.toString());
});
var tryingToReconnect = false;
// Seems not work
connection.onreconnected(function () {
tryingToReconnect = false;
loadStatus("available");
return console.log("Connection Reconnected")
});
// Seems not work
connection.onreconnecting(function (err) {
tryingToReconnect = true;
return console.log(err.message)
});
async function start() {
try {
await connection.start();
loadStatus("available");
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
loadStatus("connecting");
setTimeout(start, 5000);
}
};
connection.onclose((error) => {
//console.log("ConnectId" +connection.connectionId + "Disconnected");
//console.log(`Something went wrong: ${error}`);
connection.invoke("UserDisconnected");
});
// handle the beforeunload event
$(window).on('beforeunload', function () {
// your code here
console.log("Before unload event");
// notify the server that the user has disconnected
connection.invoke("UserDisconnected");
});
UserDisconnected method in javascript.
"use strict";
//Disable the send button until connection is established.
document.getElementById("sendButton").disabled = true;
window.onload = function () {
if (connection == undefined || connection == "undefined") {
console.log("not connect to signalr server");
} else {
if (connection._connectionState == "Connected") {
document.getElementById("sendButton").disabled = false;
}
}
}
connection.on("Chat_ReceiveMessage", function (user, message) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
// We can assign user-supplied strings to an element's textContent because it
// is not interpreted as markup. If you're assigning in any other way, you
// should be aware of possible script injection concerns.
li.textContent = `${user} says ${message}`;
});
connection.on("UserDisconnected", function (user) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
// We can assign user-supplied strings to an element's textContent because it
// is not interpreted as markup. If you're assigning in any other way, you
// should be aware of possible script injection concerns.
li.textContent = `${user} says : close browser manually`;
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("Chat_SendMessageToAll", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
UserDisconnected method in Hub class.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections.Features;
using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace SignalRMiddleawre.Hubs
{
//[Authorize]
public partial class MainHub : Hub
{
public MainHub()
{
}
/// <summary>
/// OnConnectedAsync
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
///
public override async Task OnConnectedAsync()
{
...
await base.OnConnectedAsync();
}
/// <summary>
/// OnDisconnectedAsync
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public override async Task OnDisconnectedAsync(Exception? exception)
{
...
await base.OnDisconnectedAsync(exception);
}
public async Task UserDisconnected()
{
// your code here
await Clients.All.SendAsync("UserDisconnected", Context.ConnectionId);
}
}
}