There are a few similar questions posted here but none that really addresses my needs.
I have a list of items on one page, lets call it masterlist.aspx. If I click on one these list items another page appears, i.e. details.aspx?id=something.
The page that appears has a formview control in edit mode. If the user wants to edit the data they hit an edit linkbutton and, the form is sent into edit mode, they then edit the data and click the save button, saving the data and putting the formview back in view mode.
The issue is if the user uses the browser back button to go back to the masterlist.aspx page the page is not updated, it's pulled out of the browser cache.
I have played around with the HTTP headers cache settings but can't get anything that works on all major browsers. On some browsers I get web page expired warnings. Another option is to somehow trigger a page refresh (or partial page refresh) when the page loads using client side code, but I haven't been able to figure out how to do this.
Is there any other approach or has anyone been successful with the two approaches above, or is there some way of avoiding the issue completely.
I have to do something like this in a catalog where the browse page needs to be loaded from the DB on every load because when you hit a product page it calls out to a 3rd party to get updated info, and then save it if it should be updated. This is so when you hit the back button like you're saying the data is reloaded. What I've done is added this into the page and it seems to work fine in all browsers.
public class ProductBrowser : Page
{
protected override void OnInit(EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.MinValue);
base.OnInit(e);
}
}
What about capturing the Back button keypress event, then instead of allowing it do a browser.history.back(), you can do a document.location(...) call.
Alternatively, you could capture the back event and trigger a post-back, which could do a Response.Redirect("yourpage"). This would force the browser to issue a GET statement for the designated page, and make it refresh
With Javascript a complete solution may not be possible, but there is a workaround.
http://www.boutell.com/newfaq/creating/backbutton.html
It uses a timeout function that repeatedly forces the browser to perform a 'Forward' action. Even if someone clicks the Back button, it'll bring back to the actual page, thereby nullifying the Back operation. It may cause a flicker though.
I have played around with the HTTP headers cache settings but can't get anything that works on all major browsers. On some browsers I get web page expired warnings.
How do you get to that masterlist page? If you issue an HTTP GET and prevent clients and proxies to cache it you'd have no issues navigating back to it (and still getting an updated version).
That leaves you with server side caching (with proper invalidation when any of those items change) or no caching at all.
Related
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?
I'm having trouble with a simple ASP.NET application and the back button after a post back.
The page in question has a simple form on it, some text fields etc, and a dropdown that does a postback (autopostback).
The "normal" flow is the user fills out the form and perhaps changes the dropdown. Based on the dropdown value the page content might change.
The problem I'm having is that after the user has changed the dropdown and the postback has completed then the user clicks the back button. They see a "webpage has expired" message from IE.
I've set the following:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.Private);
But that doesn't seem to have nailed the problem.
The actual Cache-Control response header reads as: private, no-cache:"Set-Cookie"
In a classic ASP application the with a Cache-Control response header of just "private" the back button behaves as expected after a "post back".
Is there anyway to force ASP.NET to set the cache-control explicitly to exactly "private"? Or any other solution that results in the back button and postbacks working well together?
Thanks!
Depending on a situation you might get away with this hack/workaround:
private void Page_PreRender(object sender, System.EventArgs e)
{
if (IsPostBack && !IsCallback)
{
Response.Write("<html><head><script>location.replace('" + Request.Path + "');\n" + "</script></head><body></body></html>\n");
Response.End();
}
}
What you're dealing with is actually an old problem. In essence, the reason that you're seeing the "web page has expired" message is that one of the techniques for disabling the "back" button has been employed. The technique sets the cache to a date in the past, therefore causing the browser to show this error if the user clicks the "back" button.
That would be this line of code:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
This has been an issue, particularly with WebForms ASP.NET because of how the postback works, compared to other frameworks.
For a thorough explanation of all the issues involved, I strongly recommend reading the article linked to below. It does not answer your question directly, but I think you will get more information out of it than a simple answer and will help you think through your options, armed with a better understanding of the issue at hand. Be sure to read parts 1 AND 2.
https://web.archive.org/web/20210927201700/http://www.4guysfromrolla.com/webtech/111500-1.shtml
I do have an idea on how to make the "back" button behave like a "back" button again, so that postbacks aren't treated as a page navigation:
Personally, I've adopted a (arguably hackish/sloppy) approach of just putting things in an UpdatePanel when I don't want the postbacl/back button conflict, since I use Ajax in most of my apps anyway. This forces the "back" button to actually go back to the previous page, rather than staing on the same page, but reverting to the control values as they were before the postback.
Most browsers reload the page from cache and do not perform a round trip server refresh.
I added Response.AppendHeader("Cache-Control", "no-store") on Page_Load but not working for Chrome, Firefox, Safari.
How to refresh page when hitting back button on browser (IE,Chrome,Firefox Safari) ?
This would be for your c# code I'm assuming.
These are my suggestions in order of most suggested to least.
Response.Cache.SetNoStore();
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.AppendHeader("pragma","no-cache");
Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
It's probably a bad idea to force this behavior because the user is expecting to see what they saw before, not a refreshed view. If that's the behavior of Chrome/Firefox/Safari then presumably the users desire this behavior because they chose that browser. If they want a refreshed view, they can refresh on their own.
That said, I often see this done with Javascript in the browser. You can hook into page load events and manually refresh if you see the page being loaded a second time. But if the client uses noscript, or otherwise doesn't support Javascript, then you're out of luck. Also, be careful to reload correctly so that users don't get taken to a new page every time they click Back and get stuck in a battle of fast-clicking reflexes.
I have a requirement to call a save method, that persists a model/object in the session, when the user leaves the page.
The page has various links that do not raise a postback but just perform a redirect. Are there any ASP.Net page life cycle methods I can hook into to perform the save without requiring a postback?
One solution could be to perform an asynchronous POST request (without waiting for a response) when the window is being unloaded:
An example using jQuery:
$(window).unload(function() {
$.post(location.href, $(document.forms[0]).serialize());
});
Although you will probably need to use a slightly different method for Chrome (found on jQuery forums):
It looks like the only way to get the
Ajax request to go through in Chrome
is to use the non-standard event
onbeforeunload. Chrome evidently
doesn't wait long enough to send the
Ajax request using onunload. It does
however wait for alerts...
Well that depends.
If you need to save values when the person leaves the page, then thats kinda hard.
What you can do, is to wrap all your links in some jquery, that says like:
Issue a Ajax Call, to AjaxSave.aspx, then it is completed, then window.location to the links href attribute.
BUT, that will only work if the person clicks on your links, not if the person just closes the browser or something.
You can also take the route to just save the stuff offen, so every time the person issues a post back, you just put the stuff in session. But that will mean that values changed from the last postback to the navigating away from the page is lost - don't know if that is an issue.
The last thing is to do like StackOverflow is doing. If you are editing stuff, it will show a warning when you leave the page, and then you have to click okay, to navigate away from the site.
I have an asp.net application that runs exclusively on IE7 (internal web site).
When a user needs to enter data, I pop up a child window with a form. When the form closes, it calls javascript:window.opener.location.reload(true) so that the new data will display on the main page.
The problem is that the browser complains that it must repost the page. Is there any way to turn this feature off?
No, but there is a solution. Its generally considered good design to use a 302 redirect immediately after someone posts data to a page. This prevents that popup from ever occuring. Allow me to elaborate.
1) The user fills in a form and submits data via POST.
2) The backend receives the data and acts upon it.
3) Instead of returning the content to the user, the backend issues a 302 redirect as soon as its done processing the page (possibly redirecting the user back to the exact same url, if need be)
4) The page that the user will see is the page you told their browser to redirect to. They will load up the redirected page with a standard GET request. If they try to refresh the page, it will not repost the data. Problem solved.
This is a problem with the usual "postback" way of ASP.NET. If you need to reload a page without this warning, this page must come from a GET, not a POST. You could do a Response.Redirect("...") yourself. But this will destroy the use of viewstate.
asp.net mvc fixes this issue, not an ie7 only problem but a security feature of most browsers. No fix that I know of except you could just update the content in the main form with js rather than reloading the whole page
It's because the page in window.opener comes from a POST Request
Maybe you can use
javascript:window.opener.location = window.opener.location; to do just a GET request if the data can be fetched without a POST.
I do not believe that there is a way to do that. Instead, why not direct the parent window to a page without a reload.
javascript:window.opener.location='your url'
AFAIK, not via your scripts.
You might try:
window.opener.location = '#';
It should circumvent the browser reposting. And, you can adjust the hash name as needed.
If you move from page1 to page2, and want to disable the browser from going back to page 1,then add the following at the top of page1.
<script>
if(window.history.forward(1) != null)
window.history.forward(1);
</script>