asp.net-mvcasp.net-corebrowsersignalrreal-time

trying to detect browser close event using SignalR


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;
     });
  });

Solution

  • Test Result

    enter image description here

    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);
            }
    
        }
    }