locked
New Item added multiple times upon refresh RRS feed

  • Question

  • User1293550733 posted
    I created an Editable DataGrid in WebMatrix. It contains an Add New Item button to add a new row to the database. The problem is aftre adding the new row, if you hit refresh, the row is added again with all of the same data. How do I keep this from happening when the page is refreshed?
    Friday, December 3, 2004 3:27 PM

All replies

  • User-721478817 posted
    You mean the refresh button on the browser? Does it pop up a box telling you that must click the retry button to post the data? If so, you're basically clicking the Add New Item button again (from the browser's point of view). If what you want to do is refresh the datagrid after you add a new row, just call your function that binds the grid to the datasource right after all your button click event code.
    Friday, December 3, 2004 4:36 PM
  • User-158764254 posted

    You can detect a browser Refresh read this: http://msdn.microsoft.com/en-us/library/ms379557(VS.80).aspx I've implemented code based on dino's and it works great. The code only detects a Refresh that occurs AFTER the page has been posted back at least once. I found dino's solution more complex than necessary. I was able to integrate the entire concept into my pagebase class without the extra httpHandler.

     

    Friday, December 3, 2004 5:20 PM
  • User1293550733 posted
    I have already added the code to bind the grid right after the new row is added. Everything works perfectly when you click Addew, then Save. The problem is....if the user wants to refresh the grid and just hits F5, when the previous action was adding a new row. Then it adds the same row again.
    Thursday, December 16, 2004 12:17 PM
  • User-158764254 posted
    and that is correct browser behavior. when you refresh by using the F5 key, the original post is repeated. if it was an Add action, then it gets added again. you need to code for this possibility. read the link i already posted.
    Thursday, December 16, 2004 1:11 PM
  • User-721478817 posted
    Yea or you can build a "middleman" page that actually does the adding of the new row and then redirects back to the page that called it, therefore if someone presses f5 or refresh, it just refreshes the page w/ no adding functionality.. Press Add Row Button -- store dataset (or whatever) obj in session or context and redirect to addRow.aspx. -- add a new row to the obj and redirect back to previous page. The Commerce starter kit uses this method to prevent the addition of multiple items to the shopping cart.
    Thursday, December 16, 2004 2:56 PM
  • User743145481 posted
    It's also the primary reason I dislike being forced into using PostBacks for easy data management. Of course, the simplicity of using txtMyTextbox.Text versus Request.Form["txtMyTextbox"] does have its advantages as well. Give and take, give and take.
    Thursday, December 16, 2004 9:35 PM
  • User-158764254 posted
    the "middleman" page is an option, but you would have to create the extra middleman page for every page with an action. The postback refresh detection takes only a little code to set up, and if you implement it in a base page class (everybody is using base page classes right?!!) then each page can wrap their actions in a new page property. If Not IsPostBackRefresh() Then -- action goes here End If
    Friday, December 17, 2004 8:51 AM
  • User1146730029 posted
    mbanavige, you said you created a less complex version of this. Is there any way you can let us see this? Also, how would you us it on a page one you created it? Just give us an example please.
    Friday, December 17, 2004 9:01 AM
  • User1477435862 posted
    mbanavige, I hope your plagiarizing! If you don't know what I'm talking about - fair enough. If you do - I know the truth. jagdipa, Here's an article on Detecting Page Refresh that I wrote, based on the Dino Esposito article.
    Friday, December 17, 2004 11:14 AM
  • User-158764254 posted
    ::Here's an article on Detecting Page Refresh that I wrote, based on the Dino Esposito article. not plagiarizing...Dino gets all the credit :-) since my version wouldn't exist without his code. I was merely trying to convey that Dino's version can be used as a basis for a simpler implementation. The version "I wrote" is based on the version Dino published.
    Friday, December 17, 2004 11:51 AM
  • User1146730029 posted
    Thanks for that. I dont want to sound picky, but is there a VB version I can look at? It would take me an age to convert it as I havent done C for about 4 years. Also, does this solution work on all browsers? I have just started using Firefox (like it, like it alot), and found that my website misbehaves outside of IE.
    Monday, December 20, 2004 3:44 AM
  • User1477435862 posted
    You can use this translator to convert the code from C# to VB.NET. And to answer your second question, it's a purely server-side implementation (has nothing to do with the client) and so doesn't depend on which browser is being used.
    Monday, December 20, 2004 7:55 AM
  • User1477435862 posted
    > not plagiarizing...Dino gets all the credit That wasn't what I meant. Of course Dino should get the appropriate level of credit, which he does in my article, however I posted a link to my article in this thread, back at the beginning of November, and it just seemed convenient that you're now talking about your version that is extremely similar to mine. I know that it's perfectly feasible that you have developed a completely independent version, that just so happens to work in the same way as mine - only you know the truth. Anyway, that's all I'm going to say on the subject.
    Monday, December 20, 2004 8:28 AM
  • User-158764254 posted
    never saw your link. i originally read dinos article in aspnetpro mag some time ago then i stumbled across the bedrock article in msdn Sounds like we arrived at the same conclusion... Dino's implementation was unnecessarily complex. I had emailed him with my comments. no reply of course. rest assurred - had i gotten my info from your article, i'd have referenced you instead of dino. I just peeked at your article. It seems we've boilded it down to a similar level of complexity although my code looks more like dino's than yours. I opted to implement my refresh check in the override of onInit in my base class (<15 lines of code). I'm not using any viewstate overrides. I also changed the extra property name from IsRefresh to IsPostBackRefresh. When i tested Dinos original code, it seem to be reporting false for refreshes that occurred without a postback. This was the point i had emailed dino on and also the reason i renamed the property to IsPostBackRefresh. i.e. it only works AFTER you've posted back atleast once.
    Monday, December 20, 2004 9:27 AM
  • User1477435862 posted
    mbanavige, Please accept my apologies. I had a bad experience at University and cannot abide plagiarism. That said I shouldn't jump to conclusions either! It's reassuring that you came to the same conclusion and am quite intrigued as to what your solution is. I opted against using Init or Load, to make inheritance easier.
    Monday, December 20, 2004 11:21 AM
  • User-158764254 posted
    ::I opted against using Init or Load, to make inheritance easier how do the viewstate overrides make inheritance easier than an init override? my solution is a single private sub that gets call in the init override it initializes a private var to track the refresh status using the same technique as dino, a "ticket" is added to the form as a hidden form field and the last ticket processed is stored in the session. perhaps this could be even more compact, but once i got it running, i moved on the other things... Private Sub DetectPostBackRefresh() 'initialize the F5 postback refresh detector Dim lastTicketProcessed As Integer = CType(HttpContext.Current.Session(Constants.KeyRefreshTicket), Integer) Dim thisTicket As Integer If HttpContext.Current.Request(Constants.KeyRefreshFormField) Is Nothing Then thisTicket = lastTicketProcessed + 1 'assume any request without a ticket is not a postbackrefresh and issue a new ticket Else thisTicket = CType(HttpContext.Current.Request(Constants.KeyRefreshFormField), Integer) End If If (thisTicket > lastTicketProcessed) OrElse (thisTicket = lastTicketProcessed AndAlso thisTicket = 0) Then 'new request HttpContext.Current.Session(Constants.KeyRefreshTicket) = thisTicket 'mark our ticket as "processed" _isPostBackRefresh = False Else 'postback refresh _isPostBackRefresh = True End If Dim newTicket As Integer = CType(HttpContext.Current.Session(Constants.KeyRefreshTicket), Integer) + 1 RegisterHiddenField(KeyRefreshFormField, newTicket.ToString(CultureInfo.InvariantCulture)) 'replace the ticket in the page with a new updated ticket End Sub
    Monday, December 20, 2004 11:59 AM
  • User1477435862 posted
    >::I opted against using Init or Load, to make inheritance easier >how do the viewstate overrides make inheritance easier than an init override? I meant "easier" in that Init and Load are common methods that developers use. By using one of those two methods any sub-classes implementing its own Init or Load must explicitly call the base class's method, in order to invoke the Is[PostBack]Refresh mechanism. If a relatively novice developer was using the mechanism, and they weren't aware of the pitfalls, they could get into some real difficulty - especially if they were defining Page_Load in the .aspx page. On the other hand LoadViewState(...) and SaveViewState() are rarely overridden and, as they intrinsically use a hidden field, there is no need to register to a new hidden field. We could debate this forever, and there are Pro's and Con's for both solutions, but I think we've both done a pretty good job. :-)
    Monday, December 20, 2004 1:41 PM
  • User-158764254 posted
    hmmmm..... In my pages base-class that contain the init override, at the end of the override, i have added a call to MyBase.OnInit(e) for each override i add to my base class, i always add a MyBase.MethodCall So, the init method of the page itself is called without any additional work required by the developer.
    Monday, December 20, 2004 2:53 PM
  • User1888952456 posted
    hey guys, that's a very interesting and good thread here.

    i translated mbanavige's code into C# more or less. it works great in asp.net 2.0 final.
    thanks a lot @ll developers who had the idea handling this postback/refresh problem!


    CustomBasePage.cs:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;

    public class CustomBasePage : System.Web.UI.Page
    {
       
    bool _isPostBackRefresh;
       
       
    public bool IsPostBackRefresh
       {
          get
          {
             return (_isPostBackRefresh);
          }
       }

       void
    DetectPostBackRefresh()
       {
          int lastTicketID = 0;
          int actualTicketID = 1;
          int newTicketID;

          if
    (HttpContext.Current.Session["TicketID"] != null)
          {
             lastTicketID =
    int.Parse(HttpContext.Current.Session["TicketID"].ToString());
             actualTicketID =
    int.Parse(HttpContext.Current.Request["__TICKET"]);
          }

          if
    (actualTicketID > lastTicketID)
          {
             HttpContext.Current.Session["TicketID"] = actualTicketID;
             _isPostBackRefresh =
    false;
          }
          else
             _isPostBackRefresh = true;

          newTicketID = actualTicketID + 1;
          ClientScript.RegisterHiddenField(
    "__TICKET", newTicketID.ToString());
       }

       protected override void OnLoad(EventArgs e)
       {
          DetectPostBackRefresh();
          base.OnLoad(e);
       }
    }

    Monday, January 30, 2006 10:48 AM
  • User1888952456 posted
    hey guys, that's a very interesting and good thread here.

    i translated mbanavige's code into C# more or less. it works great in asp.net 2.0 final.
    thanks a lot @ll developers who had the idea handling this postback/refresh problem!


    CustomBasePage.cs:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;

    public class CustomBasePage : System.Web.UI.Page
    {
       
    bool _isPostBackRefresh;
       
       
    public bool IsPostBackRefresh
       {
          get
          {
             return (_isPostBackRefresh);
          }
       }

       void
    DetectPostBackRefresh()
       {
          int lastTicketID = 0;
          int actualTicketID = 1;
          int newTicketID;

          if
    (HttpContext.Current.Session["TicketID"] != null)
          {
             lastTicketID =
    int.Parse(HttpContext.Current.Session["TicketID"].ToString());
             actualTicketID =
    int.Parse(HttpContext.Current.Request["__TICKET"]);
          }

          if
    (actualTicketID > lastTicketID)
          {
             HttpContext.Current.Session["TicketID"] = actualTicketID;
             _isPostBackRefresh =
    false;
          }
          else
             _isPostBackRefresh = true;

          newTicketID = actualTicketID + 1;
          ClientScript.RegisterHiddenField(
    "__TICKET", newTicketID.ToString());
       }

       protected override void OnLoad(EventArgs e)
       {
          DetectPostBackRefresh();
          base.OnLoad(e);
       }
    }

    Monday, January 30, 2006 11:07 AM
  • User798903548 posted

    Here's also another great article on this problem, with multiple solutions, and timed tests between them.

    http://aspalliance.com/687#Page2

    NC...

     

    Monday, January 30, 2006 12:53 PM