ASP.NET Web Form and F5 refresh issues - asp.net

I have an ASP.NET Web Form (C#) that users fill out, it has a couple of drop down lists that cause post backs and some validation that causes post backs. I also use a couple of different update panels. One panel is visible for user input and the other panel appears after the user clicks submit and the data is added to the database. The confirmation panel (the last panel) also displays a confirmation number to the user.
After the last panel displays, I would like to prevent the page from reloading when the user presses F5 or refresh. The reason is, I don't want the user to accidentally click refresh or F5 and lose the confirmation number and message. When the user presses F5, the browser interprets it as wanting to load a new page and at that point the session is cleared (as indicated in code below).
My first thought was to reprint the message and confirmation number and make sure that the panel holding it stayed visible. I was going to do this in the else section of the code below - but since there are multiple postbacks and they all trigger the page load, that doesn't work, unless there is someway to determine if the postback is the result of a form element or the f5 key.
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
Session.Clear();
GetList();
}
}
catch (Exception ex)
{
//Do something();
}
}
I've seen a few different posts that recommend using Javascript, but I am avoiding that if possible, in the remote chance that someone has javascript turned off.
Here is the flow of the program:
User opens form, fills in fields in the contactpanel and the clicks submit. The fields are validated using ASP.NET server validation controls and if everything is good, the data is sent to the database and a confirmation number is returned. Finally, the contactpanel is set to visibility=false and the confirmationpanel is set to visibility=true.
Hope this helps. Appreciate any suggestions.
Thanks,

Move your content that's on the final screen (the confirmation) to an entirely new page. Whatever data is saved to get to that confirmation should go in some type of data storage (like a database), and then whatever ID or variables the visitor needs to pull that information should go in a Session var. This way when the user refreshes the page, they will still see the content as you intend. It's pretty much how we had to do all forms back in the day anyway.
For instance:
~/form_page.aspx
- User lands
- Fills in information
- Post backs save data as the user progresses
- Save all data collected to a resource such as a database
- Save an ID to access that information to a Session variable
- Redirect user to...
~/form_thankyou.aspx
- On load, get the Session variable needed to pull the information
- Retrieve information from the resource
- Display results to user
(That's not actual code, I was just having trouble with the formatting.)
Using this technique will also make it easier on your SEO/Metrics team to track conversions (even though there are plenty of other ways).

Related

ASP.net Protect Against Pasted Submit Button With In-Browser Developer Tools?

This is not a cross-site attack because it happens on the same website.
Before we render to the browser, we figure out in server-side whether to render a button or not based on whether the user has sufficient credit in their account (example case). So, if they have insufficient credit, the check out button doesn't even make it to the page on page load.
Here's what they did:
Go to a purchase product page when they have sufficient credit. The check out button shows.
They look at Inspector (FireFox) or any other in-browser developer tool and copy the html input element that submits the form.
They purchase as normal. Now, they have insufficient credit.
They go to another purchase product page, and of course, the check out button will no longer show (because it didn't even make it on page load in the first place).
They open up their in-browser developer tool and paste the input element copied from the other previous page when they had sufficient credit. The button shows up on the rendered page. They click it, then they proceed as if they had sufficient credit.
The problem is, the submit button's event handler in code behind is unaware of the existence or non-existence of that submit button, and will execute if called, and that we give it a hard-coded id.
The obvious solution would be to do a credit vs. price check [again] on the click event handler. From inside the event handler, is there a way to determine whether the control existed on page load? I figure that the sender parameter would not be null if they pasted a control in-browser, so there's not much help there.
Any solutions on this?
The only safe solution to this is to check if the user has sufficient credits ON THE SERVER after the postback occurs.
protected void OnSubmit(object sender, eventargs e)
{
if (product.Price > User.Credits) {
throw new Exception();
}
purchase();
}
If you use the check the button approach then they can still use the JavaScript console to call __doPostBack
Never rely on the client side for authorization
You could store in ViewState whether the button was rendered or not; this is encrypted and cannot be changed on the client. If you set it as ViewState["ButtonRendered"] = true;, then you can check this to see if it's true or false, and act accordingly.
Because of the nature of the user opening up multiple browsers, and other tricks, I would 100% recommend you do another database query to make sure they have sufficient credit, and if not, display an error to the user. That would be the absolute best way of handling it. What would keep them from opening up firefox and chrome, and trying to attempt to simultaneously purchase two different items?

ASP.NET Page Life Cycle Issues

Apparently I am not familiar with the Life Cycle of a page in ASP.NET. This became apparent when I wanted to dispose of a Session variable after I left the page. I did what made the most sense:
protected void Page_Unload(object sender, EventArgs e)
{
Session.Remove("ServiceSearch");
}
What I didn't know is that this would be called when I go from AND to the page. What I am wanting to do is dispose of that Session variable whenever the user leaves the page. How do I do this?
Page_Unload refers to unloading the Page object right before it is disposed after parsing and creating the page. It has nothing to do with leaving the page. Like #Nick says, there is really no good way to tell that, except to control every exit path. And you can't, because you can't control when the user hits back, or goes to google.com and then pastes in the url they were just at into the browser, etc.
If you want to remove the Session variable just so it doesn't get re-used unintentionally, a better solution is to overwrite the Session variable every time you enter the page, and just let it be disposed with the session on its own time when the session expires.
Session data is useful for storing data beyond the lifetime of a page. If you don't want to store it beyond the life of a page then Session data is not for you here.
If the user leaves the page via a link you could possibly create a link button that is hooked up to a method on the same page. That method would remove the session and do the redirect.
I would hope there is a better solution though. Although, from my understand, there is no page event to use in your case because the page would have to reload to execute the remove session code. When the user leaves via some link the page is not reloaded.
You may possibly be able to handle it via javascript. I've been in situations where I wanted to leave and I got a popup box about some bs. You could probably use the same technique to fire AJAX to remove the session.
I faced a similar situation on php login- a logged-in user could use the arrow back and forth to login page. So, I simply add :
session_start();
session_unset();
session_destroy();
above the html script of the login page so that if the logged-in user arrowed back, the session is both unset and destroyed. Any attempt to arrow forward will only lead to the login page-requesting user login credentials-essentially, the user is logged out any time they arrow back!
Hope this helps!
Alfred

Back button must not go to previous page after signing out

I am developing an asp.net web site and I am not using inbuilt authentication controls of asp.net. I have created manually tables for users for site.
What I want is as follows
After logging in user can access the pages (that is already done)
When user press sign out (user goes to specific page - example - default.aspx)
Now when user press "back" button of browser, it must not go to previous page (that is done in Yahoo pages - I want to implement the same)
To prevent users from seeing the previous page when pressing the back button you need to instruct the browser not to cache this page:
Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
Response.Cache.SetValidUntilExpires(false);
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
You could put this code in all authenticated pages, thus preventing them from being cached on client browsers.
For a page not to be cached the browser needs to respond appropriately to caching instructions, but there is no guarantee that this will work on every browser! (An appropriately evil person could write their own browser to ignore caching information, or write a proxy to strip it out...)
So you can't get this to work 100% of the time, but you're always going to face the problem that a user can easily take a screenshot, print out a page, save a copy on their disk, etc. once you've fed a page to them anyway...
the answer for you question is:
for When user press sign out. ( user goes to specific page - example - default.aspx )
you can add a LinkButton as Signout link and in the click event handler you can write
Response.Redirect("Default.aspx");
for Now when user press "back" button of browser It must not go to previous page
//add the following code to your code behind of the page
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string strDisAbleBackButton;
strDisAbleBackButton = "<script language="javascript">\n";
strDisAbleBackButton += "window.history.forward(1);\n";
strDisAbleBackButton += "\n</script>";
ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "clientScript", strDisAbleBackButton);
}
refer to csharpdotnetfreak.blogspot.com

How to Track F5/Refresh in ASP.Net

I am using VS 2005, C# 2, ASP.Net 2.0
I am unable to find out how to track that user pressed F5/Ctrl+F5/ Open a new Window(Ctrl + N) in ASP.Net.
I know that there is a Page.IsPostBack property, which tells that a page is loaded in response to an action taken by user.
I am just curious to know, that why isn't there a property as IsRefresh or Page.IsRefresh in ASP.Net, which will return true,
whenever user takes any of the above actions.
Is there a way to know this?
Actually my problem is that i have a DLL using which all of my aspx pages are inherited, I have to
insert some values in a table whenever the page is opened for the first time that's it, if user just opens the page or do not take any action,
an entry should be inserted into the database, but as far as I have tried, I controlled it anyhow using the Page.IsPostBack property, but I got stuck
in the refresh case, as it is inserting records unconditionally.
Similar to using a function in Global.asax (as others have suggested) you could use a session variable "flag". When the page first loads set a session variable and then just check against it in your page load function:
if (Session("visited") != "true"
//page has not been visited, log visit to DB
Just make sure you set the session flag sometime after the above check during the page load.
It won't be exact (sessions can timeout while a page is active, users can completely leave the site and come back in the same browser and the session stays alive, etc) but for your tracking it is much better than counting every page hit in the DB.
Perhaps you want the Session_Start method in the Global.asax file, which will be triggered once at the start of each user session?
In your Global.asax file, add or edit the method:
void Session_Start(object sender, EventArgs e)
{
}
why isn't there a property as IsRefresh or Page.IsRefresh in ASP.Net
Because ASP.NET cannot possibly know. The browser does not send any information that could allow it to determine whether the page is being requested due to a refresh or normal load. You will need to reconsider your requirements: what is the actual purpose of the database logging?
Session_Start method in Global.asax file is fired every time when a browser session is started. You can use this method to count number of unique users on your website.
Session_End method in Global.asax is fired when a session ends (explicitly or timedout). So you can decrement the count here.
Hope the above to example uses of these methods helps you understand how you can use them.
Because of the stateless nature of HTTP protocol there is no way to tell apart the initial load from the refresh
As has already been said. This isn't possible. A request issued due to a refresh is no different to a request issued the first time the page is loaded.
It sounds to me like you are trying to track page views somehow. This is certainly possible though it will require some work on your part. Your best bet is probably to log the URL of the page. You may also want to include the query string in order to differentiate between page loads for different pieces of data (if this happens in your application). You will also want to log the ID of the current user, and the ID of their session.
You can then make sure that you don't insert two page views for the same user for the same page in the same session, effectively filtering out any reloads of a page.
You do need to be aware that this isn't the same as detecting a refresh, what you are detecting is two page views in the same session, this could be a refresh, or it could be use of the back button, or just reloading from the address bar.
My suggestion would be to create a cookie on very first load, then on Page_Load check to see if the cookie exists. If it does, don't insert the record. You can use Session_End to destroy or create the cookie as someone suggested if that works with your application's architecture.

ASP.NET passing values between redirect & postback

First of all, thanks for reading.
I will describe my situation as explicitly as I can.
I have a page where users can leave comments.
Here's the commenting flow
A-1. 'comment' button is clicked
A-2. a modal popup with a textbox is shown using ModalPopupExtender in ajaxtoolkit.
A-3. User types a comment in the textbox, and click "ok".
However, when user is not logged in, expected behavior changes.
B-1. 'comment' button is clicked
B-2. a Login modal-popup with id & pwd textbox is shown.
B-3. User types ID & pwd, and click ok.
B-4. Comment-modal-popup is shown
B-5. user types a comment and click ok.
I have a PROBLEM handing this case.
When B-3 occurs, page is posted back, i log the user in, update session object, and I Response.Rediect() the page to itself to display correct logged-in status (i have to..).
After redirect, in Page_Load(), I need to check some values to show Comment-Modal-Popup.
But I'm not sure how..
Here's what i considered
ViewState
i just can't use it since the page was redirected not posted back.
QueryString
I could have add "showCommentPopup=1" on URL when redirecting, but that will leave unwanted QueryString in URL. I don't want users to misuse it.
Session
I actually used Session object. Before redirection, I set Session[ "ShowCommentPopup" ] to true. In Page_Load() if it is set, i remove it and show the popup.
using Session like i did doesn't work correctly when user opens same page in multiple tabs.
user opens two tabs(in Firefox) with same URL
user follows steps from B-1 to B-3 in first tab.
before the page is redirected between B-3 and B-4, user refreshes second tab.
if the timing is right, comment-popup is shown in the second tab.
I expect to hear great insights from stackoverflow..
I haven't tried this but I think if you store your ShowCommentPopup flag in the HttpContext.Items collection instead of the session and then use Server.Transfer instead of Response.Redirect you should be able to achieve the desired results.
HttpContext.Items is a dictionary that can be used to store data whose lifetime is the lifetime of the request. This means a second request from a different tab or window will have a different HttpContext.Items dictionary.
Server.Transfer is somewhat like Response.Redirect in that it allows you to load a "different" URL instead of the original. However, while Reponse.Redirect initiates a new request, Server.Transfer transfers the existing request to the new page on the server.
A better explanation of the differences between Response.Redirect and Server.Transfer can be found here.
Example
bool showCommentPopup = false;
if (HttpContext.Current.Items["ShowCommentPopup"] != null)
{
showCommentPopup = (bool)HttpContext.Current.Items["ShowCommentPopup"];
}
//...
HttpContext.Current.Items["ShowCommentPopup"] = true;
You've clearly thought your solutions through! I'm guessing the problem with the Session was that they could comment on a different page than the one they logged into. You could get around this by storing the session var, not as a bool, but as the page to show it on:
var uniqueString = this.ToString() + uniquePageID;
if (Session["ShowCommentPage"].ToString() == uniqueString)
//show modal & remove session var
Now your program only "breaks" when the user visits the same object in two different windows, logs in on Window #1, and refreshes on Window #2. And it's not really breaking since they wind up commenting on the same object either way.
The reason I used uniquePageID, is cause I'm figuring you have a template page ("showObject.aspx") with arguments on which to show ("showObject.aspx?objectID=3"). In order to make sure the comment is left on the same ID, it needs to be present in uniqueString

Resources