page refresh is firing the event again

ASP.NET doesn't provide a way to do it directly.

There are a few techniques, on the other hand, to avoid duplicate submission:

  1. Redirect after submission. This is the worst one. Even if it avoids duplicate submission, it is not acceptable in a modern web application from the users point of view.

  2. Track submissions per form, per session. When the user submits a form for the first time, remember this in the session. If another submission happens, try to determine if it must be discarded or not (in some cases, it must not; for example, if I edit my answer on StackOverflow once, I would be able to do it twice if I need to).

  3. Disable submission with JavaScript after the first submission. This avoids in some cases the situation when either the user double-clicks the submission button, or clicks it for the first time, waits and thinks that the form was not submitted, thus clicking for the second time. Of course, don't rely on this one: JavaScript may be disabled, it will work on double-click but not on F5 refresh, and in all cases the technique is not completely reliable.

As an illustration, let's try to implement the second one.

Let's say we have a comment box this.textBoxComment which let the users add a new comment on a page of a blog. The submission is done like this:

private void Page_Load(object sender, System.EventArgs e)
{
    if (this.IsPostBack)
    {
        string comment = this.ValidateCommentInput(this.textBoxComment.Text);
        if (comment != null)
        {
            this.databaseContext.AddComment(comment);
        }
    }
}

If the user clicks twice, the comment will be posted twice.

Now, let's add some session tracking:

private void Page_Load(object sender, System.EventArgs e)
{
    if (this.IsPostBack)
    {
        if (this.Session["commentAdded"] == null)
        {
            string comment = this.ValidateCommentInput(this.textBoxComment.Text);
            if (comment != null)
            {
                this.databaseContext.AddComment(comment);
                this.Session.Add("commentAdded", true);
            }
        }
        else
        {
            // TODO: Inform the user that the comment cannot be submitted
            // several times.
        }
    }
}

In this case, the user will be able to submit a comment only once. Every other comment will be automatically discarded.

The problem is that the user may want to add comments to several blog posts. We have two possible ways to allow that. The easy one is to reset the session variable on every non-postback request, but this will allow the user to submit a post on one page, load another page, than hit refresh on the first one, thus submitting the comment twice but not being able to add a comment on the second page any longer.

private void Page_Load(object sender, System.EventArgs e)
{
    if (this.IsPostBack)
    {
        if (this.Session["commentAdded"] == null)
        {
            string comment = this.ValidateCommentInput(this.textBoxComment.Text);
            if (comment != null)
            {
                this.databaseContext.AddComment(comment);
                this.Session.Add("commentAdded", true);
            }
        }
        else
        {
            // TODO: Inform the user that the comment cannot be submitted
            // several times.
        }
    }
    else
    {
        this.Session.Remove("commentAdded");
    }
}

The more advanced one is to track in session the list of pages where the comment was submitted.

private void Page_Load(object sender, System.EventArgs e)
{
    List<string> commentsTrack = this.Session["commentAdded"] as List<string>;
    string blogPostId = this.ValidatePostId(this.Request.QueryString["id"]);
    if (blogPostId != null)
    {
        if (this.IsPostBack)
        {
            this.AddComment(commentsTrack);
        }
        else
        {
            if (commentsTrack != null && commentsTrack.Contains(blogPostId))
            {
                commentsTrack.Remove(blogPostId);
            }
        }
    }
}

private void AddComment(List<string> commentsTrack)
{
    if (commentsTrack == null || !commentsTrack.Contains(blogPostId))
    {
        string comment = this.ValidateCommentInput(this.textBoxComment.Text);
        if (comment != null)
        {
            this.databaseContext.AddComment(comment);
            if (commentsTrack == null)
            {
                commentsTrack = new List<string>();
            }

            commentsTrack.Add(blogPostId);
            this.Session["commentAdded"] = commentsTrack;
        }
    }
    else
    {
        // TODO: Inform the user that the comment cannot be submitted
        // several times.
    }
}