C#lock关键字,我想我用错了

Cie*_*iel 4 locking asp.net-mvc-3

我最近在ASP.NET MVC应用程序中发布了多个表单的问题.情况基本上是,如果有人故意敲定提交按钮,他们可以强制数据被多次发布,尽管验证逻辑(服务器和客户端)都是为了禁止这一点.这是因为他们的帖子会在Transaction.Commit()方法可以在初始请求上运行之前完成(这都是在nHibernate中完成的)

MVC ActionMethod看起来有点像这样......

public ActionResult Create(ViewModelObject model)
{
 if(ModelState.IsValid)
 {
  // ...

  var member = membershipRepository.GetMember(User.Identity.Name);
  // do stuff with member
  // update member
 }
}
Run Code Online (Sandbox Code Playgroud)

提出了很多解决方案,但是我找到了C#lock语句并尝试了一下,所以我改变了我的代码看起来像这样......

public ActionResult Create(ViewModelObject model)
{
 if(ModelState.IsValid)
 {
  // ...
  var member = membershipRepository.GetMember(User.Identity.Name);
  lock(member) {     
     // do stuff with member
     // update member
  }
 }
}
Run Code Online (Sandbox Code Playgroud)

有效!我的测试人员都不能重现这个bug了!我们一直在抨击它超过一天,没有人能找到任何缺陷.但我对这个关键字并不是那么经验.我再次查看以澄清......

lock关键字通过获取给定对象的互斥锁,执行语句,然后释放锁,将语句块标记为关键部分

好的,这是有道理的.这是我的问题.

这太简单了

这个解决方案看似简单,直接,清晰,高效和干净.这是方式太简单了.我知道比认为复杂的东西更简单的解决方案更好.所以我想问更有经验的程序员......

有什么不好的事情我应该知道吗?

jga*_*fin 7

不,不是那么容易.锁定仅在使用相同实例时才有效.

这不起作用:

public IActionResult Submit(MyModel model)
{
    lock (model)
    {
       //will not block since each post generates it's own instance
    }
}
Run Code Online (Sandbox Code Playgroud)

你举的例子可以正常工作.这完全取决于是否在nhibernate中启用了二级缓存(从而返回相同的用户实例).请注意,它不会阻止任何内容发布到数据库,只是每个帖子将按顺序保存.

更新

另一种解决方案是return false;在按下时添加到提交按钮.它会阻止按钮多次提交表单.

这是一个jquery脚本,将为您解决问题(它将通过所有提交按钮,并确保它们只提交一次)

$(document).ready(function(){
    $(':submit').click(function() {
        var $this = $(this);
        if ($this.hasClass('clicked')) {
            alert('You have already clicked on submit, please be patient..');
            return false;
        }
        $this.addClass('clicked');
    });
});
Run Code Online (Sandbox Code Playgroud)

添加它你布局或javascript文件.

UPDATE2

请注意,jquery代码在大多数情况下都有效,但请记住,任何具有一点编程知识的用户都可以使用例如HttpWebRequest向您的Web服务器发送垃圾邮件.这不太可能,但可能会发生.我要说的是,你不应该依赖客户端代码来处理问题,因为它们可以被规避.