如果两个请求在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集合中分配一个锁对象来执行相同的操作吗?

最佳答案

仅当您使用实现HttpSessionStateBase但不重写SyncRoot属性以执行除抛出NotImplementedException以外的其他操作的自定义会话类时,此危险才存在。 HttpSessionStateWrapper类和HttpSessionState类必须实现并重写SyncRoot方法。因此,只要您是通过HttpSessionStateWrapperHttpSessionState类而不是自定义类访问Session,这将很好地工作。

10-08 02:22