使用Session.SyncRoot锁定每个会话有什么危险?

时间:2013-06-04 16:36:01

标签: c# asp.net asp.net-mvc-3 session thread-safety

如果两个请求在ASP.NET MVC应用程序中非常接近,我会遇到以下代码的竞争条件:

var workload = org.Workloads.SingleOrDefault(p => ...conditions...);
if (workload == null) {
    workload = org.CreateWorkload(id);
}

workloadorg是EntityFramework对象。对CreateWorkload的调用会向数据库中的Workloads表添加一行。 (我们真的应该在表上使用UNIQUE约束强制执行此操作,但我现在不能表中包含一些脏数据。)对包含此代码的Action方法的后续调用将抛出SingleOrDefault遇到满足条件的多行时的异常。

所以要解决这个问题,我想lock这些代码行。我不希望每次请求都使用静态锁定对象,因为这会降低每个用户的网站速度。我想做的是使用Session.SyncRoot进行锁定。即。

Workload workload;
lock (Session.SyncRoot) 
{
    workload = org.Workloads.SingleOrDefault(p => ...conditions...);
    if (workload == null) {
        workload = org.CreateWorkload(id);
    }
}

然而,我不是ASP.NET专家,并且在文档和ReSharper中出现了一些警告信号,即它可以抛出NotImplementedExceptions或为null。但是,测试显示这很好用。

那么,ASP.NET专家说,使用Session.SyncRoot的风险是什么?作为替代方案,如果Session.SyncRoot“真的有风险”,我可以在Session启动时在Session集合中分配一个锁对象来做同样的事情吗?

1 个答案:

答案 0 :(得分:2)

如果您使用实现HttpSessionStateBase的自定义会话类但不覆盖SyncRoot属性以执行除了抛出NotImplementedException之外的其他操作,则仅存在危险。 HttpSessionStateWrapper类和HttpSessionState类DO实现并覆盖SyncRoot方法。因此,只要您通过HttpSessionStateWrapperHttpSessionState类访问会话而不是自定义类,这就可以正常工作。