2012-03-21 227 views
5

我有一个ASP.NET MVC 3应用程序,它有一个名为Create后的行动:防止重复表单提交

[HttpPost] 
public virtual ActionResult Create(Issues issues) 
{ 
    if (ModelState.IsValid) 
    { 
     context.Issues.Add(issues); 
     context.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 
    return View(issues); 
} 

如果我双击提交按钮错误,它会创建2个问题。有没有一种方法来防止这种情况,没有使用javascript和禁用按钮,我认为使用RedirectToAction的整个使用是通过使用Post/Redirect/Get设计模式来防止这种情况?

+1

你能简单地添加一些像if(!context.Issues.Exists(logic))吗? – 2012-03-21 11:10:07

+1

只需单击时禁用提交按钮! – gdoron 2012-03-21 11:19:08

+0

有没有这种方法称为存在? – CallumVass 2012-03-21 11:19:25

回答

4

你提到的(邮政/重定向/获取设计模式)的图案防止页面双重张贴刷新,因为最后一个动作是GET,而不是POST。

如果要防止双重张贴双击,你可以:

1. Disable the button after click 
2. Maintain a unique index on 'Issues' and look for duplicates 
3. Maintain something in session that gives you an indication of a double post 

而且有可能是几个方面......我想禁用按钮可能是最容易的,因为你无论如何,它都会重定向到另一个页面。

+0

对于上面的例子来说,这很好,但是我所关心的是更高级的例子,例如Ajax.BeginForm,它只会更新页面的一部分 – CallumVass 2012-03-21 11:33:58

+0

@BiffBaffBoff - 为了防止双击客户端(AJAX POST),您可以直接阻止UI直到响应返回(同步),或者禁用按钮(异步),或者实现一些服务器端来检测它。 – 2012-03-21 11:43:01

+0

嗨克里斯,这正是我现在所做的。我已禁用该按钮,直到响应恢复。再次感谢 – CallumVass 2012-04-04 10:46:16

1

当您向用户展示表单时,您可以生成IssueId,然后检查您在Create方法中是否对此类标识没有问题,例如跳过此类请求。

+0

那么它只会创建继续追加ID的问题是IssueId是我的PK领域,因此对于每个新创建的问题,它都会有一个新的Id(2,3,4,5等)。 – CallumVass 2012-03-21 11:20:39

2

最简单的办法我能想到的是使用Session:

if (ModelState.IsValid) 
{ 
    DateTime now = DateTime.Now; 
    if (Session["LastAdd"] == null || (now - (DateTime)Session["LastAdd"]).TotalMilliseconds > 1000) 
    { 
     //first time, or more than a second passed since last addition 
     context.Issues.Add(issues); 
     context.SaveChanges(); 
     Session["LastAdd"] = now; 
    } 
    return RedirectToAction("Index"); 
} 
+0

对不起,我不使用会话作为其Windows身份验证应用程序 – CallumVass 2012-03-21 11:18:09

+0

@BiffBaffBoff - 开始使用“会话”变量。 – 2012-03-21 11:21:56

+0

@Biff会话变量与认证无关。是什么让你以这种方式思考? – 2012-03-21 12:40:52

5

简单的解决方案!

点击时禁用提交按钮。 结束。

$('submitButtonId').click(function(){ 
    $(this).prop('disabled', true); 
    $(this).attr('disabled', 'disabled'); // for jQuery versions < 1.6. 
}); 
+1

使用此解决方案,如果用户在点击和上传信息到服务器之间存在网络问题,那么无法挽救表单中的信息。如果用户花了5分钟时间填写表单,他们会感到不安。更好的方法可能只是在网络成功或失败之前将其禁用。 – 2014-05-01 17:53:03

+0

这不适用于JavaScript禁用? – 2016-02-29 04:32:36

+0

@AlexAngas,JavaScript禁用时没有任何工作。我认为没有js就没有好的方法。 (_Shadow Wizard_下面的回答是硬编码1000毫秒,这远非理想情况,如果用户网络连接速度很慢,该怎么办?) – gdoron 2016-02-29 13:24:00

0

PRG模式不会阻止这种情况,因为其中的P动作需要时间(通常是这种情况),用户可以再次提交表单(通过点击或浏览器刷新),这会导致PRG模式“失败”。

请注意,恶意用户也可以通过快速连续运行多个http帖子来绕过所有客户端措施。

以上所有的解决方案是使用以下方法检查服务器端的重复提交,如我所述,here

为方便起见,我引述:

“如果你使用一个隐藏的防伪标记在你的形式(如你 应该),你可以标记上缓存防伪先提交和 从缓存中,如果需要删除标记,或到期后的时间设定量的缓存项 。

然后,您将能够检查与对缓存 每个请求的具体形式是否已经提交并拒绝如果有的话。“