Close/kill the session when the browser or tab is closed - asp.net

Can somebody tell me how can I close/kill the session when the user closes the browser? I am using stateserver mode for my asp.net web app. The onbeforeunload method is not proper as it fires when user refreshes the page.

You can't. HTTP is a stateless protocol, so you can't tell when a user has closed their browser or they are simply sitting there with an open browser window doing nothing.
That's why sessions have a timeout - you can try and reduce the timeout in order to close inactive sessions faster, but this may cause legitimate users to have their session timeout early.

As said, the browser doesn't let the server know when it closes.
Still, there are some ways to achieve close to this behavior. You can put a small AJAX script in place that updates the server regularly that the browser is open. You should pair this with something that fires on actions made by the user, so you can time out an idle session as well as one that has closed out.

As you said the event window.onbeforeunload fires when the users clicks on a link or refreshes the page, so it would not a good even to end a session.
http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx describes all situations where window.onbeforeonload is triggered. (IE)
However, you can place a JavaScript global variable on your pages to identify actions that should not trigger a logoff (by using an AJAX call from onbeforeonload, for example).
The script below relies on JQuery
/*
* autoLogoff.js
*
* Every valid navigation (form submit, click on links) should
* set this variable to true.
*
* If it is left to false the page will try to invalidate the
* session via an AJAX call
*/
var validNavigation = false;
/*
* Invokes the servlet /endSession to invalidate the session.
* No HTML output is returned
*/
function endSession() {
$.get("<whatever url will end your session>");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
}
// Wire up the events as soon as the DOM tree is ready
$(document).ready(function() {
wireUpEvents();
});
This script may be included in all pages
<script type="text/javascript" src="js/autoLogoff.js"></script>
Let's go through this code:
var validNavigation = false;
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
A global variable is defined at page level. If this variable is not set to true then the event windows.onbeforeonload will terminate the session.
An event handler is attached to every link and form in the page to set this variable to true, thus preventing the session from being terminated if the user is just submitting a form or clicking on a link.
function endSession() {
$.get("<whatever url will end your session>");
}
The session is terminated if the user closed the browser/tab or navigated away. In this case the global variable was not set to true and the script will do an AJAX call to whichever URL you want to end the session
This solution is server-side technology agnostic. It was not exaustively tested but it seems to work fine in my tests

Please refer the below steps:
First create a page SessionClear.aspx and write the code to clear session
Then add following JavaScript code in your page or Master Page:
<script language="javascript" type="text/javascript">
var isClose = false;
//this code will handle the F5 or Ctrl+F5 key
//need to handle more cases like ctrl+R whose codes are not listed here
document.onkeydown = checkKeycode
function checkKeycode(e) {
var keycode;
if (window.event)
keycode = window.event.keyCode;
else if (e)
keycode = e.which;
if(keycode == 116)
{
isClose = true;
}
}
function somefunction()
{
isClose = true;
}
//<![CDATA[
function bodyUnload() {
if(!isClose)
{
var request = GetRequest();
request.open("GET", "SessionClear.aspx", true);
request.send();
}
}
function GetRequest() {
var request = null;
if (window.XMLHttpRequest) {
//incase of IE7,FF, Opera and Safari browser
request = new XMLHttpRequest();
}
else {
//for old browser like IE 6.x and IE 5.x
request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
}
return request;
}
//]]>
</script>
Add the following code in the body tag of master page.
<body onbeforeunload="bodyUnload();" onmousedown="somefunction()">

I do it like this:
$(window).bind('unload', function () {
if(event.clientY < 0) {
alert('Thank you for using this app.');
endSession(); // here you can do what you want ...
}
});
window.onbeforeunload = function () {
$(window).unbind('unload');
//If a string is returned, you automatically ask the
//user if he wants to logout or not...
//return ''; //'beforeunload event';
if (event.clientY < 0) {
alert('Thank you for using this service.');
endSession();
}
}

Not perfect but best solution for now :
var spcKey = false;
var hover = true;
var contextMenu = false;
function spc(e) {
return ((e.altKey || e.ctrlKey || e.keyCode == 91 || e.keyCode==87) && e.keyCode!=82 && e.keyCode!=116);
}
$(document).hover(function () {
hover = true;
contextMenu = false;
spcKey = false;
}, function () {
hover = false;
}).keydown(function (e) {
if (spc(e) == false) {
hover = true;
spcKey = false;
}
else {
spcKey = true;
}
}).keyup(function (e) {
if (spc(e)) {
spcKey = false;
}
}).contextmenu(function (e) {
contextMenu = true;
}).click(function () {
hover = true;
contextMenu = false;
});
window.addEventListener('focus', function () {
spcKey = false;
});
window.addEventListener('blur', function () {
hover = false;
});
window.onbeforeunload = function (e) {
if ((hover == false || spcKey == true) && contextMenu==false) {
window.setTimeout(goToLoginPage, 100);
$.ajax({
url: "/Account/Logoff",
type: 'post',
data: $("#logoutForm").serialize(),
});
return "Oturumunuz kapatıldı.";
}
return;
};
function goToLoginPage() {
hover = true;
spcKey = false;
contextMenu = false;
location.href = "/Account/Login";
}

It is not possible to kill the session variable, when the machine unexpectly shutdown due to power failure. It is only possible when the user is idle for a long time or it is properly logout.

For browser close you can put below code into your web.config :
<system.web>
<sessionState mode="InProc"></sessionState>
</system.web>
It will destroy your session when browser is closed, but it will not work for tab close.

Use this:
window.onbeforeunload = function () {
if (!validNavigation) {
endSession();
}
}
jsfiddle
Prevent F5, form submit, input click and Close/kill the session when the browser or tab is closed, tested in ie8+ and modern browsers, Enjoy!

Related

Flutter: is Dialog on top of Navigator (stack)?

How do I determine whether some dialog is being displayed or top of the stack is a dialog?
I have an async function that pushes a dialog (Like post request with loading dialog). When the response comes, loading the dialog closed(pop) then message dialog is pushed.
But the problem is:
If I send multiple requests, sometimes the loading screen stays on top...
bool dialogIsVisible(BuildContext context) {
bool isVisible = false;
Navigator.popUntil(context, (route) {
isVisible = route is PopupRoute;
return !isVisible;
});
return isVisible;
}
You can check if a Dialog is on top of the Navigator object by doing a little verification:
void _verifyDialog(context) {
var _isDialogOnTop = false;
var stackCount = 0;
Navigator.popUntil(context, (route) {
if (!_isDialogOnTop && route.toString().contains("_DialogRoute")) {
_isDialogOnTop = true;
}
else{
stackCount++;
}
return _isDialogOnTop || stackCount > 0;
});
print (_isDialogOnTop);
}

Older asynchronous messages overwriting newer ones

We are developing a document collaboration tool in SignalR where multiple users can update one single WYSIWYG form.
We are struggling getting the app to work using the KeyUp method to send the changes back to the server. This causes the system to overwrite what the user wrote after his first key stroke when it sends the message back.
Is there anyway to work around this problem?
For the moment I tried to set up a 2 seconds timeout but this delays all updates not only the "writer" page.
public class ChatHub : Hub
{
public ChatHub()
{
}
public void Send(int id,string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(id,message); //id is for the document id where to update the content
}
}
and the client:
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
//console.log("Declare a proxy to reference the hub.");
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (id, message) {
var encodedValue = $('<div />').text(id).html();
// Add the message to the page.
if (encodedValue == $('#hdnDocId').val()) {
$('#DiaplayMsg').text(message);
tinyMCE.activeEditor.setContent("");
tinyMCE.get('txtContent').execCommand('insertHTML', false, message); //!!!
}
};
// Start the connection.
$.connection.hub.start().done(function (e) {
//console.log("Start the connection.");
if ($('#hdnDocId').val() != '') {
tinyMCE.activeEditor.onKeyUp.add(function (ed, e) {
var elelist = $(tinyMCE.activeEditor.getBody()).text();
var content = tinyMCE.get('txtContent').getContent();
function Chat() {
var content = tinyMCE.get('txtContent').getContent();
chat.server.send($('#hdnDocId').val(), content); //send a push to server
}
typewatch(Chat, 2000);
});
}
});
});
var typewatch = function () {
var timer = 0;
return function (Chat, ms) {
clearTimeout(timer);
timer = setTimeout(Chat, ms);
}
} ();
</script>
Hello, here is an update of the client KeyUp code. It seems to be working but I would like your opinion. I've used a global variable to store the timeout, see below:
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
//console.log("Declare a proxy to reference the hub.");
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (id, message) {
var encodedValue = $('<div />').text(id).html();
var currenttime = new Date().getTime() / 1000 - 2
if (typeof window.istyping == 'undefined') {
window.istyping = 0;
}
if (encodedValue == $('#hdnDocId').val() && window.istyping == 0 && window.istyping < currenttime) {
function Update() {
$('#DiaplayMsg').text(message);
tinyMCE.activeEditor.setContent("");
tinyMCE.get('txtContent').execCommand('insertHTML', false, message); //!!!
// tinyMCE.get('txtContent').setContent(message);
window.istyping = 0
}
Update();
}
};
// Start the connection.
$.connection.hub.start().done(function (e) {
//console.log("Start the connection.");
if ($('#hdnDocId').val() != '') {
tinyMCE.activeEditor.onKeyUp.add(function (ed, e) {
var elelist = $(tinyMCE.activeEditor.getBody()).text();
var content = tinyMCE.get('txtContent').getContent();
function Chat() {
//alert("Call");
var content = tinyMCE.get('txtContent').getContent();
chat.server.send($('#hdnDocId').val(), content);
window.istyping = new Date().getTime() / 1000;
}
Chat();
});
}
});
});
var typewatch = function () {
var timer = 0;
return function (Chat, ms) {
clearTimeout(timer);
timer = setTimeout(Chat, ms);
}
} ();
Thanks,
Roberto.
Is there anyway to work around this problem?
Yes, by not sending the entire document to the server, but document elements like paragraphs, table cells, and so on. You can synchronize these after the user has stopped typing for a period, or when focus is lost for example.
Otherwise add some incrementing counter to the messages, so older return values don't overwrite newer ones arriving earlier.
But you're basically asking us to solve a non-trivial problem regarding collaborated document editing. What have you tried?
"This causes the system to overwrite what the user wrote"
that's because this code isn't making any effort to merge changes. it is just blindly overwriting whatever is there.
tinyMCE.activeEditor.setContent("");
tinyMCE.get('txtContent').execCommand('insertHTML', false, message);
as #CodeCaster hinted, you need to be more precise in the messages you send - pass specific changes back and forth rather re-sending the entire document - so that changes can be carefully merged on the receiving side

IE8 post file targeting iframe, arrives on server as null

I have a form with just an input:file in it and the form targets a named iframe. when the user selects a file it automatically posts the form to the server. This works in IE10/firefox/chrome, but in IE8 the File parameter on my controller method is null when IE8 posts the form. Has anyone else encountered this and know of any solutions, why isn't IE8 actually posting the file data?
ClientSide:
function createFileUploadForm()
{
var frameName = 'fileUploadFormFrame';
var fileValue;
var fileUploadCallback = function()
{
//do stuff when the server responds after receiving the file
};
var fileInputChangedCallback = function(event)
{
if(fileInput.value != fileValue)
{
fileValue = fileInput.value;
form.submit();
}
};
var iFrame = document.createElement('iframe');
iFrame.name = frameName
document.body.appendChild(iFrame);
var form = document.createElement('form');
form.action = 'a/valid/url';
form.method = 'post';
form.enctype = 'multipart/form-data';
form.target = frameName;
var fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.name = 'File';
fileInput.accept = '.spc';
fileValue = fileInput.value;
//all browsers except IE8
//add event listener to fileInput onChange event -> fileInputChangedCallback
//IE8 fix
//add event listener to fileInput onFocus event -> fileInputChangedCallback
form.appendChild(fileInput);
document.body.appendChild(form);
}
ServerSide:
[HttpPost]
public ActionResult UploadFile(HttpPostedFileBase File)
{
//do stuff with File, but in IE8 File parameter is null
}
the problem was that IE8 requires an additional encoding property on the form to be set:
var form = document.createElement('form');
form.action = 'a/valid/url';
form.method = 'post';
form.enctype = 'multipart/form-data';
form.encoding = 'multipart/form-data'; //this additional line fixes the IE8 problem I was having
form.target = frameName;

Master page button event Overloading by content page button event when enter key is pressed

I have two search options:
1. On Master Page there is a text box and button for search.
2. on content page there is form for with two texboxes and a button for search.
Now whenever i press enter key from keyboard, the masterpage button event is fires.
I mean in every case when I press enter key from keyboard the same event is called.
I want If someone fill the content page search form and press enter key, it fires content page event.I am doing it like this:
<script language="javascript">
function HandleEnterKey(e) {
var key;
if (window.event)
key = window.event.keyCode; //IE
else
key = e.which; //firefox
if (key == 13) {
if (txtSearchHasFocus) {
alert(txtSearchHasFocus);
document.getElementById("ctl00_bluheader1_btnSearch1").click();
}
else if (txtBusinessNameHasFocus || txtLicNumberHasFocus) {
alert(txtBusinessNameHasFocus);
alert(txtLicNumberHasFocus);
alert(document.getElementById("ctl00_ContentPlaceHolder1_btnSearch"));
e.cancel = true;
document.getElementById("ctl00_ContentPlaceHolder1_btnSearch").click();
}
else return false;
}
//return false;
}
</script>
but not working
Please someone help me...
regards
It seems you have KeyPress event handler for a whole document. You should handle KeyPress only for your specific textbox. I.e. you should use different event handlers for masterpage textbox and for content page texboxes. Here is an example using jQuery:
<script language="javascript" type="text/javascript">
$(document).ready(function() {
$('#tbMasterId').keypress(function(e) {
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$('#ctl00_bluheader1_btnSearch1').click();
return false;
} else {
return true;
}
});
$('#tbContent1Id,#tbContent2Id').keypress(function(e) {
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$('#ctl00_ContentPlaceHolder1_btnSearch').click();
return false;
} else {
return true;
}
});
});
</script>

A simple secenario to implement JavaScript ASP.NET C#, question rephrased

I had asked this question before, but I got no correct answer.
So, this is a simple thing:
textbox.text='user typing';
Button: store the value to a variable and a database.
Very simple, nothing to it.
But there should be no post back, that is the page must not load again.
Try Ajax? I tried it, but it is not working.
I lost a lot of time trying to implement this using JavaScript Ajax and read many many posts.
But for some reason I cannot implement the functionality correctly.
var xmlHttp;
var is_ie = (navigator.userAgent.indexOf('MSIE') >= 0) ? 1 : 0;
var is_ie5 = (navigator.appVersion.indexOf("MSIE 5.5")!=-1) ? 1 : 0;
var is_opera = ((navigator.userAgent.indexOf("Opera6")!=-1)||(navigator.userAgent.indexOf("Opera/6")!=-1)) ? 1 : 0;
//netscape, safari, mozilla behave the same???
var is_netscape = (navigator.userAgent.indexOf('Netscape') >= 0) ? 1 : 0;
function btnClick(){
if (strReportURL.length > 0)
{
//Create the xmlHttp object to use in the request
//stateChangeHandler will fire when the state has changed, i.e. data is received back
// This is non-blocking (asynchronous)
xmlHttp = GetXmlHttpObject(handler);
//Send the xmlHttp get to the specified url
xmlHttp_Get(xmlHttp, "AjaxHanlder.aspx?Data="+txtData.Text,handler);
}
}
//stateChangeHandler will fire when the state has changed, i.e. data is received back
// This is non-blocking (asynchronous)
function handler()
{
//readyState of 4 or 'complete' represents that data has been returned
if (xmlHttp.readyState == 4 || xmlHttp.readyState == 'complete')
{
//Gather the results from the callback
var result = xmlHttp.responseText;
//Populate the innerHTML of the div with the results
document.getElementById('lblResult').innerHTML = result;
}
}
// XMLHttp send GET request
function xmlHttp_Get(xmlhttp, url,handler) {
xmlhttp.open('GET', url, true);
xmlhttp.onreadystatechange = handler;
xmlhttp.send(null);
}
function GetXmlHttpObject(handler) {
var objXmlHttp = null; //Holds the local xmlHTTP object instance
//Depending on the browser, try to create the xmlHttp object
if (is_ie){
//The object to create depends on version of IE
//If it isn't ie5, then default to the Msxml2.XMLHTTP object
var strObjName = (is_ie5) ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP';
//Attempt to create the object
try{
if(!objXmlHttp)
objXmlHttp = new ActiveXObject(strObjName);
//objXmlHttp.onreadystatechange = handler;
}
catch(e){
//Object creation errored
alert('IE detected, but object could not be created. Verify that active scripting and activeX controls are enabled');
return;
}
}
else if (is_opera){
//Opera has some issues with xmlHttp object functionality
alert('Opera detected. The page may not behave as expected.');
return;
}
else{
// Mozilla | Netscape | Safari
objXmlHttp = new XMLHttpRequest();
objXmlHttp.onload = handler;
objXmlHttp.onerror = handler;
}
//Return the instantiated object
return objXmlHttp;
}
///AJAX HANDLER PAGE
public class AjaxHandler : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if(Request.QueryString["Data"]!=null)
{
StoreYourData(Request.QueryString);
}
}
}

Resources