Refresh page repeat database transaction? - c#

I have over 30 aspx pages, i have discovered a problem recently that if i did any kind of database transaction like insert, update, delete and then after the transaction is complete i pressed F5 or refreshed the page in anyway the same is transaction occur.
I searched for a solution but all i could found is that i have to check for viewstate on each button which is impossible, cause that means there will be a lot of work. There got to be generic solution, please help me in this problem.
Edit:
Here is the code on one of the buttons which change a value in data base to either true or false:
protected void btn_Publish_Click(object sender, EventArgs e)
{
if (Convert.ToBoolean(int.Parse(hf_Published.Value.ToString())))
{
publish(false);
}
else
{
publish(true);
}
}
After the execution of the code if refreshed the page the same code is executed, i noticed that since a break point was placed on this method.

You can try this. I used this in several project and working successfully.
public bool IsRefreshed
{
get
{
if (Convert.ToString(Session["RefreshTimeStamp"]) == Convert.ToString(ViewState["RefreshTimeStamp"]))
{
Session["RefreshTimeStamp"] = HttpContext.Current.Server.UrlDecode(System.DateTime.Now.ToString());
return false;
}
else
{
return true;
}
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ViewState["RefreshTimeStamp"] = Session["RefreshTimeStamp"];
}
protected override void OnLoad(EventArgs e)
{
if (!Page.IsPostBack)
{
Session["RefreshTimeStamp"] = HttpContext.Current.Server.UrlDecode(System.DateTime.Now.ToString());
}
base.OnLoad(e);
}

There IS a generic solution, used for years by thousands of developers.
And the solution is: each time you perform an intrusive process at the server (insert/update/delete) you don't just render the page but rather you redirect the response with 302 to a fresh page with "your transaction succeeded" message.
This way, pressing the F5 will just refresh this message page, not the original page which triggers the transaction.
It is up to you whether or not this is directly applicable in your scenario.
http://en.wikipedia.org/wiki/Post/Redirect/Get

To fix this issue you could check the following:
Disable the submit button when necessary
Add some validation to your code and check for double entries
Redirect the user to another page after submit

Unless it's a real 'transaction' like payments etc. (which others already explained, do redirect etc.),
You could also try defining caching on your pages that interact with the Db or are bottlenecks for your app.
If you wanna have always live info (and it's that 'alive' type of app) then no luck with that solution (but even then), but usually, you can put some reasonable time expiration on how 'fresh' you want your data to be.
Caching ASP.NET Pages

Related

How to call Session_End when a browser is closed?

I have two questions. I will split my questions into two sections and give an overview. I'm not entirely sure of the code I need to post so if I have missed some out, please let me know and I will help.
Overview:
When the browser is closed I need to sign the user out.
Question 1:
How do I call Session_End when the browser is closed?
I did some reading on how to close it and it seems that the only way to detect if a Session has ended when a browser has been ended is by using something called 'InProc' in my web config. I gave it an attempt and it didn't seem to change anything at all. So I'm wondering if there is another way around this.
Session_End:
protected void Session_End() {
if (User.Identity.IsAuthenticated) {
}
}
Question 2: How to sign a user out on Session_End?
Once the program has called the void I need to sign the user out as it's causing a bug in my program. I am using the Authentification manager.
Session_End:
protected void Session_End() {
if (User.Identity.IsAuthenticated) {
AuthenticationManager.SignOut();
}
}
Using InProc sessions, the Session_End method is called when the session times out. This is (by default) 20 minutes after the user has last accessed your site (requested a new page). Note that these 20 minutes could have been spent carefuly reading a single page of your site - his session is still closed.
There is no way to detect when a user has closed his browser or navigated away from your site.
You need to use the Global.asax file. It should already contain this Method, all you need to do is add the guts of your code.
protected void Session_End(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
AuthenticationManager.SignOut();
}
}

ASP.NET session drop event

Is theire a way, to get noticed if an asp.net web forms session is droped (For example, the client cloeses the browser = timeout)?
We have one session for the temporary user shopping card:
HttpContext.Current.Session["UserShoppingCard"] = new UserShoppingCard();
Every thing works fine, besides the functions explanied above.
Thank you!
I would try to intercept the Session_End event in the global.asax file and put some logging in there, it might not happen right when the browser is closed but it will happen at some point anyway once the session is terminated and you can include your logic in there.
In fact the server never knows when a browser is closed or if instead a connection issue is making the client unable to connect.
As said before, complementing with code...
public class Global : System.Web.HttpApplication
{
protected void Session_End(object sender, EventArgs e)
{
//Do your things here when session ends...
}
}

Detecting refresh/postback conditions working in debug but not production

After searching the web, there seems to be a strong consensus that a good way to prevent a refresh from triggering a database access is to use a ViewState variable and Session variable to detect the condition. Here's the code in my base page class:
protected override void OnLoad( EventArgs e )
{
base.OnLoad( e );
if ( IsPostBack && ViewState["REFRESH_CHECK"] != Session["REFRESH_CHECK"] )
{
IsRefresh = true;
}
Session["REFRESH_CHECK"] = System.Guid.NewGuid().ToString();
ViewState["REFRESH_CHECK"] = Session["REFRESH_CHECK"];
}
public virtual bool IsRefresh
{
get;
private set;
}
So in my pages I have some code that looks like this:
protected void Page_Load( object sender, EventArgs e )
{
if ( !IsPostBack )
{
if ( !IsRefresh )
{
doStuffThatShouldOnlyBeDoneOnce();
}
}
}
This works perfectly while debugging, however when I run on a production system, I always get two invocations of the doStuff...() method. Of course when I debug it, there is only one call ever.
It may or may not be relevant, but I am using nested Master pages too.
Any ideas?
Oh man please do not use this code, this can break your web page. For a simple test, try to open same page with two different tabs and you will see that the solution has failed.
The only solution for the F5 refresh problem is Response.Redirect.
I have tried this soltion so I am telling you from my experience.
Half-answer
I was unable to figure out why Page_Load() is getting invoked twice in a production environment and only once in debug mode.
None of the techniques regarding refresh hitting the DB twice were working for me either.
So the approach I took was to change where the work was being done. Instead of executing the code when a new page was being loaded, I executed the code in a delegate for the button control when it was pressed prior to the redirect.
delegate( Object o, EventArgs eventArgs )
{
doStuffHere();
HttpContext.Current.Response.Redirect( "admin/Admin.aspx", false );
}
In this case, the next page needs some setup done based on the previous page, so long as I precede all redirects with this, everything is ok. This does not work if a user goes straight to a URL, but for this particular situation thats ok - the page won't be fully populated, but it won't cause an error and the user can still do work.

pass variable from page load to button click event

i am creating a page that when page load it will connect to the database to check the user status to determine which part can be shown, then user can click submit button which need to connect to the database again to update some information.
So is there a efficient way to do this? now I have to connect to the database twice or is there a method to pass variables from page load event to button click event.
Any idea? thanks
I hope I understood your question correctly. All you need to do is extract all functionality which is aware of connecting to a database and then verify permissions in a separate method. Basically, a simple Extract Method technique.
public void Page_Load(...)
{
// check whilst first loading of the page
// if you need checking each time as page loading - remove if() below
if (!IsPostBack)
{
YourConnectToDatabaseMethod(defaultParams);
}
}
public void OnButtonClick(...)
{
var params = ... grab required params;
YourConnectToDatabaseMethod(params);
}
private void YourConnectToDatabaseMethod(TypeOfParams params)
{
}
Your database connection most likely comes from a connection pool so even if you call Open, you are not actually reopening a connection but using an already opened one.

In C# asp.net is it possible to send back a valid web page half way through a method?

When I want to redirect a user who has lost session state back to the StartPage I find Response.Redirect("~/StartPage.aspx") causes the error "Response Redirect Cannot Be Called In A Page Callback". Therefore in a Page.IsCallback situation I want to add javascript to do the redirect - this works - see code below.
protected void ForceBackToStartPage()
{
if (Page.IsCallback)
{
string fullLoginUrl = ConvertRelativeUrlToAbsoluteUrl( "~/StartPage.aspx" );
string script = string.Format("window.location.href = '{0}';", fullLoginUrl);
ClientScriptManager cm = Page.ClientScript;
cm.RegisterClientScriptBlock(GetType(), "redirect", script, true);
//Response.Flush();
//Response.End();
}
else
{
Response.Redirect("~/StartPage.aspx");
}
}
After I have added the javascript in this section the code continues to process normally leaving this function and going off to other processing sections of the webpage - probematic as the user has no session data. Ideally I'd want processing of this web page to finish - and for the page to return in a valid state so that the user gets redirected.
Is this possible?
I thought Response.Flush(); Response.End(); might do the trick - but the webpage sent back to the browser causes XML Parse errors.
Further info: I check for missing session data in a few places (depending on the webpage - this code is in lots of web pages) - for instance - PageLoad and from some submit button methods.
Before the new method I used this code e.g.:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
Response.Redirect("~/StartPage.aspx");
}
...rest of processing
Now it's invoked like this:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
ForceBackToStartPage();
}
...rest of processing
so I could obviously use
else
{
...rest of processing
}
but I was hoping not to have to do that as SVN Source Control takes that to mean I've re-written the whole 'rest of processing' section. This is problematic as when I merge from a branch into the trunk it does not check I am not overwriting mods because it assumes it's all new code coming in.
Response.Redirect issues a "302 Moved" command that cannot be served asynchronously. Given that you're just registering a script when IsCallback=true, could you not also do it when IsCallback= false? Register a script that hooks up an event to the loaded event of the window and redirect the page from script instead of from the server.
I was thinking about this again recently and realised the very obvious answer. Forget nicely structured code, as being part of an error trap this is a special case, and use a return; after the 'ForceBackToStartPage' method invocation:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
ForceBackToStartPage();
return;
}
...rest of processing
}

Categories

Resources