how to prevent session abandonment for idle user (session wise) - asp.net

I have a page on my web app where users might use for potentially hours with no server interaction. all interactions are done on the page with javascript.
how can I prevent a session abandonment if I do want to have it set for 20 minutes on all other pages?
my solution is sending an empty ajax call every 10 minutes just to tickle the server, but is there any other option?

You can make a dummy ajax call to renew the session timeout.
To do this, create an empty .aspx page, and use whatever you want to load that page to renew the session. For example, a JavaScript setInterval and a jquery $.get()
If you don't fill comfortable using JavaScript and jQuery, you always can use an Ajax Timer' and another AjaxUpdatePanel`.
This guarantees that the session will keep alive while the browser is open.
Making all sessions longer doesn't look like the best possible solution.
Dependign on where you need this functionality, you can implement it on a master page, or include it where needed. You can even include it in the masterpage and enable or disable the timer.

In ASP.Net, you can change Session.Timeout before returning to extend it on that page. I have not tested whether or not it would un-extend on other subsequent requests, but it would be worth looking at.
http://msdn.microsoft.com/en-us/library/ms524319(v=vs.90).aspx

Related

Is there a way using ASP.NET to always run some server side code when a user leaves a page?

I was wondering if there is any way to always run some server side code when a user leaves a page in ASP.NET. The page Unload event is no good because that doesn't get called if someone clicks on a link. Ideally I'd also like the code to run even if the user closes the browser.
I suspect what I'm asking isn't possible, but it doesn't hurt to ask
Problem is, HTTP is a stateless protocol, so when the page has finished being served, you wont know if the user is still on the page or not.
The only way to acheive this would be a hidden piece of Javascript that constantly pings the server with it's session ID, or another similar mechanism. When the ping becomes unresponsive you can reasonably assume the page is not being viewed by the user anymore.
Here is a diagram that explains traditional HTTP message flow.
im not really sure if you can do that but i have a workaround in mind.
There is an event in the DOM called onbeforeunload. it get calls everytime a user leaves a page. you can try sending an ajax request to the server from this function.
The closest thing you can come without creating too messy a solution is to enable ASP sessions. This will create a session on the server for each visitor, who will be identified by a cookie.
After a certain amount of inactivity from the visitor, the session will be closed, and a SessionEnd event will be raised. This you can hook up to in the Global.asax file.
I will not recommend this however, because HTTP is pr. definition a session-less protocol, and using server based sessions violates this fact, and are often problematic. Many solutions that use server based sessions run into problems when the user uses the browser-back button, and resubmits a form. Because the content of the submitted form no longer corresponds the data that exists in the server session.
Also, enabling server based sessions seriously hurts the scalability of the application.
Not that I know of. You'll need to use javascript for that, and call a web service on the server side.

Client-side session timeout redirect in ASP.Net

I want to build a way to automatically redirect users to Timeout.aspx when their session expires due to inactivity. My application uses forms authentication and relies heavily on update panels within the same aspx page for user interaction, so I don't want to simply redirect after a page-level timer expires. For the same reason, I can't use '<meta http-equiv="refresh"/>'
What I want to do is create a simple ajax web service with a method called IsSessionTimedOut(), that simply returns a boolean. I will use a javascript timer to periodically call the method, and if it returns true, then redirect to Timeout.aspx. However, I don't want calling this method to reset the session timeout timer, or the session would never time out because of the service call. Is there a clean way to avoid this catch-22? Hopefully there is an easy solution that has so far eluded me.
the crux of the problem is that in AJAX apps, to provide a robust user experience you must clutter your client script with reams of code checking the status of every call and determining if a failure is due to a stale session/ticket. With a proactive approach your client script can be dramatically simplified while at the same time providing a much better user experience.
I have built a solution for this problem specifically.
It allows interactive session and forms ticket lifetime auditing without bumping the session or ticket.
Multiple browsers/tabs are no problem.
Forget the sunscreen; Remember: When doing Ajax, be proactive - You should abandon a session, a session should not abandon you ;-)
AsynchronousSessionAuditor 1.0
This is the best solution I've come up with so far, but I'm open to something better. Basically, I have a 15-minute javascript timer that is reset with every async postback. The disadvantage of this approach is that a second tab or window open in the background would cause the session to end, even if the user is actively using the application in another browser window.
Something similar to this lives on my master page. The last line of javascript adds my reset function to be triggered when any update panel refreshes:
<asp:ScriptManager ID="ScriptManager1" runat="server" ScriptMode="Release" OnAsyncPostBackError="ScriptManager1_AsyncPostBackError">
<Scripts >
<asp:ScriptReference Path="~/scripts/jquery/jquery-1.3.2.min.js" />
</Scripts>
</asp:ScriptManager>
<script type="text/javascript">
var redirectTimer = setTimeout('redirectToLogout()', 900000);
function redirectToLogout() {
window.location = "/logout.aspx";
}
function ResetTimeoutTimer() {
clearTimeout(redirectTimer);
redirectTimer = setTimeout('redirectToLogout()', 900000);
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(ResetTimeoutTimer);
</script>
Is it really critical that the timeout happen when the server-side session expires?
If you just want to force users to refresh their sessions or time them out, I would use window.setTimeout() to redirect to Timeout.aspx after a set time. The codebehind of Timeout.aspx can call Session.Abort() to kill the session, which will force the user to log back in if they want to continue.
I think this method will actually be more accurate and reliable than the Session timeout, which (in my experience) tends to vary depending on the server load and other factors.
I think that if you enable session state for your web service, and then set the SessionStateBehavior to read only in your global.asax if the web service is being hit, you should be good. You'll need to do this early in the lifecycle.
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.setsessionstatebehavior(v=VS.100).aspx
I think you are going about this the wrong way... If you absolutely can't use a simple meta-refresh (by far the easiest way to handle this) then just handle the cases where your AJAX methods return values that indicate your session has timed out. Why do you need an extra mechanism just to do this? I'm not that familiar with the UpdatePanel... but if the update fails when your session is expired, surely you can send back some "hey pardner, you need to log in again" message?

Can a single asp.net user make more than one request at a time if the Session is in use?

I am not able to make more than one request at a time in asp.net while the session is active. Why does this limitation exist? Is there a way to work around it?
This issue can be demonstrated with a WebForms app with just 3 simple aspx pages (although the limitation still applies in asp.net mvc).
Create an asp.net 3.5 web application.
There should be just three pages:
NoWait.aspx, Wait.aspx, and SessionStart.aspx
NoWait.aspx has this single nugget added between the default div tags: <%=DateTime.Now.Ticks %>. The code-behind for this page is the default (empty).
Wait.aspx looks just like NoWait.aspx, but it has one line added to Page_Load in the code-behind: Thread.Sleep(3000); //wait 3 seconds
SessionStart.aspx also looks just like NoWait.aspx, but it has this single line in its code-behind: Session["Whatever"] = "Anything";
Open a browser and go to NoWait.aspx. It properly shows a number in the response, such as: "633937963004391610". Keep refreshing and it keeps changing the number. Great so far! Create a new tab in the same browser and go to Wait.aspx. It sits for 3 seconds, then writes the number to the response. Great so far! No, try this: Go to Wait.aspx and while it's spinning, quickly tab over to NoWait.aspx and refresh. Even while Wait.aspx is sleeping, NoWait.aspx WILL provide a response. Great so far. You can continue to refresh NoWait.aspx while Wait.aspx is spinning, and the server happily sends a response each time. This is the behavior I expect.
Now is where it gets weird.
In a 3rd tab, in the same browser, visit SessionStart.aspx. Next, tab over to Wait.aspx and refresh. While it's spinning, tab over to NoWait.aspx and refresh. NoWait.aspx will NOT send a response until Wait.aspx is done running!
This proves that while a session is active, you can't make concurrent requests with the same user. Requests are all queued up and served synchronously. I do not expect or understand this behavior. I have tested this on Visual Studio 2008's built in web server, and also IIS 7 and IIS 7.5.
So I have a few questions:
1) Am I correct that there is indeed a limitation here, or is my test above invalid because I am doing something wrong?
2) Is there a way to work around this limitation? In my web app, certain things take a long time to execute, and I would like users to be able to do things in other tabs while they wait of a big request to complete. Can I somehow configure the session to allow "dirty reads"? This could prevent it from being locked during the request?
3) Why does this limitation exist? I would like to gain a good understanding of why this limitation is necessary. I think I'd be a better developer if I knew!
Here is a link talking about session state and locking. It does perform and exclusive lock.
The easiest way around this is to make the long running tasks asynchronous. You can make the long running tasks run on a separate thread, or use and asynchronous delegate and return a response to the browser immediately. The client side page can send requests to the server to check and see if it is done (through ajax most likely), and when the server tells the client it's finished, notify the user. That way although the server requests have to be handled one at a time by the server, it doesn't look like that to the user.
This does have it's own set of problems, and you'll have to make sure that account for the HTTP context closing as that will dispose certain functionality in the asp.net session. One example you'll probably have to account for is probably releasing a lock on the session, if that is actually occurring.
This isn't too surprising that this could be a limitation. Each browser would have it's own session, before the advent of ajax, post back requests were synchronous. Making the same session handle concurrent could get really ugly, and I can see how that wouldn't be a priority for the IIS and ASP.NET teams to add in.
For reasons Kevin described, users can't access two pages that might write to their session state at the same time - the framework itself can't exert fine-grained control over the locking of the session store, so it has to lock it for entire requests.
To work around this, pages that only read session data can declare that they do so. ASP.NET won't obtain a session state write lock for them:
// Or false if it doesn't need access to session state at all
EnableSessionState="ReadOnly"

How to capture session state

I have a asp .net master page application and one content page has a number of controls on it.
I want to store the content/state of those controls in the session state whenever a user navigates to another content page.
My question is, how do I know when to capture the control state? Is there an event of some type I can use to trigger a procedure?
Thanks in advance for any info.
Bill
There aren't any real "global" server side event handlers that you can use to detect when the user is going to another page (or even just hitting the back button in the browser).
The best bet is to simply write a method in your master page that will save your session state and then execute a Response.Redirect() to the location specified. Then make all of your links go through this method when you need to track session state.
Presumably they are navigating away from that page via a control that you have provided them (button, link, etc.) You can trap the action on the server side at that point and cache your state.
What about using session variables?
See this link for more info:
ASP.Net Session
There's a number of ways to maintain state. There are trade-offs no matter which version you use. For example, I wouldn't use session variables on an app that is load-balanced across multiple servers; you're not guaranteed to get the same server for each request, and the state is stored on a server-by-server basis.
It's hard to beat this
Session["myState"] = 7; // bad example
for simplicity, though. :)

Notifying the user after a long Ajax task when they might be on a different page

I have an Ajax request to a web service that typically takes 30-60 seconds to complete. In some cases it could take as long as a few minutes. During this time the user can continue working on other tasks, which means they will probably be on a different page when the task finishes.
Is there a way to tell that the original request has been completed? The only thing that comes to mind is to:
wrap the web service with a web service of my own
use my web service to set a flag somewhere
check for that flag in subsequent page requests
Any better ways to do it? I am using jQuery and ASP.Net, if it matters.
You could add another method to your web service that allows you to check the status of a previous request. Then you can use ajax to poll the web service every 30 seconds or so. You can store the request id or whatever in Session so your ajax call knows what request ID to poll no matter what page you're on.
I would say you'd have to poll once in a while to see if request has ended and show some notifications, like this site does with badges for example.
At first make your request return immediately with something like "Started processing...". Then use a different request to poll for the result. It is not good neither for the server nor the client's browser to have long open HTTP sessions. Moreover the user should be informed and educated that he is starting a request that could take some time to complete.
To display the result you could have a"notification area" in all of your web pages. Alternatively you could have a dedicated page for this and instruct the user to navigate there. As others have suggested you could use polling to get the result.
You could use frames on your site, and perform all your long AJAX requests in an invisible frame. Frames add a certain level of pain to development, but might be the answer to your problems.
The only other way I could think of doing it is to actually load the other pages via an AJAX request, such that there are no real page reloads - this would mean that the AJAX requests aren't interrupted, but may cause issues with breaking browser functionality (back/forward, bookmarking, etc).
Since web development is stateless (you can't set a trigger/event on a server to update the client), the viable strategy is to setup up a status function that you can intermittently call using a javascript timer to check whether your code has finished executing. When it finishes, you can update your view.

Resources