Prevent Form Resubmission in ASP.Net (without redi

2019-04-29 09:19发布

问题:

I have a master page with a Form element (<form runat="server">), a content page with a Button element (<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Sync" />), and a Code Behind page that contains the Button1_Click function.

The user comes to the page and clicks the button. The Code Behind code executes (on the server) in which it updates some tables in a database. The last thing the Code Behind code does is to set the InnerHTML of a Span element on the content page with a success or failure message.

That all works great. The problem is if the user refreshes the page, the Form is resubmitted and the browser asks if that's really what the user wants. If the user responds in the affirmative then the Code Behind code is re-executed and the database is updated again. If the user responds negatively, then nothing happens.

Re-executing the Code Behind code is not a big deal. It won't hurt anything. But it's not really the behavior I want.

I know I can do a redirect back to the page with Response.Redirect() but then the user never sees my success or failure message. I should mention that the message is really more than just "Success" or "Failure" otherwise I suppose I could add something to the QueryString on the Redirect.

Is there a way to reset the Form element from the Code Behind code so that if the user refreshes the page the Form is not resubmitted?

The master page...

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="IntuitSync.SiteMaster" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:ipp="">
    <head runat="server">
    </head>
    <body>
        <form runat="server">
            <div runat="server" id="mainContetntDiv">
                <asp:ContentPlaceHolder ID="MainContent" runat="server" />
            </div>
        </form>
    </body>
</html>

The content...

<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/Site.master" CodeBehind="SyncToCloud.aspx.cs" Inherits="IntuitSync.SyncToCloud" %>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Sync" />
    <span runat="server" id="SyncStatus"></span>
</asp:Content>

The Code Behind...

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Web;

namespace IntuitSync
{
    public partial class SyncToCloud : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            /*
                Do a bunch of stuff and put the results in syncResults which is a List.
            */
            SyncStatus.InnerHtml = string.Join("", syncResults.ToArray()); // I'd rather do this...
            //Response.Redirect(Request.Url.PathAndQuery, true);  // ...and not do this.
        }
    }
}

Any and all help is greatly appreciated.

回答1:

The issue is you're doing a form POST which, if the user subsequently refreshes the page, does what it's supposed to do: resubmit the POST. There is no way around it. Therefore, the options available to you are as follows:

  1. Redirect to a confirmation page, passing the operation results to the confirmation page in some way (typically reload from some data repository if it's something that's not feasible for a query string/cookie/etc.).
  2. Redirect to the same page, but pass the success message via a query string parameter (or go silly and store it in the session/ViewState/what-have-you-silliness).
  3. Instead of posting, do a form get since it seems you aren't posting any values, only initiating some sort of server-side processing. To do so simply change your form from a post to a get, or just do a link. The danger here is you shouldn't be doing any transformative/destructive operations in any get operation.

You probably would be happiest with the last option, but it all depends on what "do a bunch of stuff and put the results in syncResults..." really entails.



回答2:

i would suggest going into JASON route

on SyncToCloud.aspx.cs

[System.Web.Services.WebMethod]
    public static string updateSyncStatus()
    {
        /*
                Do a bunch of stuff and put the results in syncResults which is a List.
            */
            SyncStatus.InnerHtml = string.Join("", syncResults.ToArray()); // I'd rather do this...
            //Response.Redirect(Request.Url.PathAndQuery, true);  // ...and not do this.
    }

on SyncToCloud.aspx

function SyncStatus(){
                $.ajax({
                            type: "POST",
                            async:true,
                            url: "syncToCloud.aspx/updateSyncStatus",
                            data: <if have anydata>,
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            success: function (msg) {
                                if (msg.d == "Success") {                                    
                                    //Set message on some lable or do something
                                } else {
                                    //Proceed to show message on wrong password
                                }
                            } 
                        }); 
            }

Markup on buutton

<asp:Button ID="Button1" runat="server" OnClientClick="SyncStatus(); return false;" Text="Sync" />