ASP.NET не предоставляет способ сделать это напрямую.
С другой стороны, существует несколько методов, позволяющих избежать дублирования представления:
Перенаправление после отправки. Это худший. Даже если это позволяет избежать повторной отправки, это неприемлемо в современном веб-приложении с точки зрения пользователей.
Отслеживание заявок по форме, за сеанс . Когда пользователь отправляет форму в первый раз, запомните это в сеансе. Если произойдет другая отправка, попробуйте определить, следует ли ее отменить или нет (в некоторых случаях это не должно происходить; например, если я один раз отредактирую свой ответ в StackOverflow, я смогу сделать это дважды, если потребуется).
Отключить отправку с помощью JavaScript после первой отправки. В некоторых случаях это позволяет избежать ситуации, когда пользователь дважды щелкает кнопку отправки или нажимает ее в первый раз, ожидает и думает, что форма не была отправлена, и, таким образом, щелкает второй раз. Конечно, не полагайтесь на это: JavaScript может быть отключен, он будет работать при двойном щелчке, но не при обновлении F5, и во всех случаях техника не совсем надежна.
В качестве иллюстрации попробуем реализовать второй.
Допустим, у нас есть поле для комментариев this.textBoxComment
, которое позволяет пользователям добавлять новый комментарий на страницу блога. Представление делается так:
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);
}
}
}
Если пользователь щелкнет дважды, комментарий будет опубликован дважды.
Теперь давайте добавим отслеживание сеанса:
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.
}
}
}
В этом случае пользователь сможет оставить комментарий только один раз. Все остальные комментарии будут автоматически удалены.
Проблема в том, что пользователь может захотеть добавить комментарии к нескольким постам в блоге. У нас есть два возможных способа сделать это. Самый простой - сбросить переменную сеанса при каждом запросе без обратной передачи, но это позволит пользователю отправить сообщение на одной странице, загрузить другую страницу, а затем нажать кнопку обновления на первой странице, отправив комментарий дважды, но не возможность добавления комментария на вторую страницу.
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");
}
}
Более сложным является отслеживание в сеансе списка страниц, на которые был отправлен комментарий.
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.
}
}