Asp.net OptimisticConcurrencyException with System.Web.Providers

Asp.net OptimisticConcurrencyException with System.Web.Providers,asp.net,sql-server,asp.net-mvc,optimistic-concurrency,Asp.net,Sql Server,Asp.net Mvc,Optimistic Concurrency,我正在SQL Server中使用来自Microsoft的新会话。SQL Server上旧的会话实现需要一个作业(每分钟运行一次)来清除过期的会话。新的一个会在每次请求时进行检查和清除。因为我实际上是在SQLAzure中运行的,所以我没有SQL代理来安排作业,所以这听起来是一种合理的方式(不,我不想为会话支付Azure缓存) 问题是,当多个用户同时访问该站点时,他们都试图同时清除相同的过期会话,而第二个用户获得乐观并发异常 System.Data.OptimisticConcurrencyExce

我正在SQL Server中使用来自Microsoft的新会话。SQL Server上旧的会话实现需要一个作业(每分钟运行一次)来清除过期的会话。新的一个会在每次请求时进行检查和清除。因为我实际上是在SQLAzure中运行的,所以我没有SQL代理来安排作业,所以这听起来是一种合理的方式(不,我不想为会话支付Azure缓存)

问题是,当多个用户同时访问该站点时,他们都试图同时清除相同的过期会话,而第二个用户获得乐观并发异常

System.Data.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Web.Providers.DefaultSessionStateProvider.PurgeExpiredSessions()
   at System.Web.Providers.DefaultSessionStateProvider.PurgeIfNeeded()
   at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData)
   at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

我使用ELMAH来记录错误,这是以某种频率出现的。在我尝试配置ELMAH以忽略错误之前,有人知道一种方法来阻止错误的发生吗?是否有我缺少的新提供程序的某些配置?

请下载提供程序的较新版本,可在此处找到:。我们已经更新了清理过期会话的方式,以异步运行并处理错误条件。如果它不能纠正您的问题,请告诉我们。

我在NuGet上发布了一个问题(http://www.nuget.org/packages/System.Web.Providers),并得到了业主的快速响应。经过一段时间的前后对比,他们确实对此进行了修复,但将在下一次更新中发布


这里有一个建议,微软并不太热衷于支持这一点,但我的经验是相反的,并且一直得到很好的支持。

这个软件包有一个我称之为bug的漏洞。进程外会话状态的前提是多个实例可能正在管理会话状态清理。在这种情况下,所有实例都在运行此方法

private void PurgeExpiredSessions()
{
    using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
    {
        foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
        {
            entities.DeleteObject(entity);
        }
        entities.SaveChanges();
        this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
    }
}
问题在于,一个实例在其他实例之前删除实体,而实体会抛出文章中描述的错误。我要求软件包作者发布源代码或修复此问题。。我未经测试的文本编辑器修复程序是添加公共虚拟,这样就可以重写该方法或只是对其进行更改

private void PurgeExpiredSessions()
{
    using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
    {   
        var sqlCommand = @"DELETE dbo.Sessions WHERE Expires < GETUTCDATE()";
        entities.ExecuteStoreCommand(sqlCommand);
        this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
    }
}

感谢包装团队的快速响应和大力支持

我也遇到了同样的问题。您发现如何解决此问题了吗?我能想到的唯一方法就是反编译代码?任何建议据我所知,微软并不真正支持这些提供商。我内心的愤世嫉俗者说,他们正试图驱使Azure用户为缓存付费。我希望有人能证明我错了。最后,我们放弃了它,回到了一个纯SQL Server提供商那里。我们已经需要另一台服务器来调度其他无关的作业,所以我们也将清除过期会话作业放在那里。对不起,我没有更好的报告。你解决这个问题了吗?我自己也遇到了同样的问题。从下面的回复来看,它可能会在更新版本(1.2,5月31日发布)中修复。我还没有回来测试它,而且看起来我不会了。使用最新的Azure SDK,您可以从实例运行缓存,而无需为其专业缓存服务器付费。它正在预览中,但到目前为止似乎运行良好。这里团队中的其他人将会话移动到运行缓存而不是SQL(当我们在Azure上时,当我们在EC2上时,它将返回到完整的SQL Server)。感谢更新。我将在本周晚些时候或者在我完成当前项目后的下个月初尝试看一看。是否有任何类型的公共更改日志可用?虽然我将会话从默认提供程序中移出,但我仍在使用成员资格/角色。我将此标记为解决方案,但我尚未测试它是否确实解决了问题。我们已经转移到Azure缓存预览进行会话,因此测试这一点对我来说不再可行。我在使用Sql Azure和最新的2012年6月nuget时遇到了完全相同的问题。在我的例子中,我正在逃离azure共址缓存,因为它由于存储故障(缓存状态管理器)和新实例没有更新新ip地址的依赖实例(azure有许多未知的单点故障)而导致了几次中断。Scott,这个通用提供商软件包太棒了!但是有没有关于这个错误的后续行动?azure中的两个实例中,似乎有一个比另一个更适合PurgeExpiredSessions()。您所说的“发布问题”是指“联系了包的所有者”,还是有其他方法可以在NuGet上发布问题?许多其他的微软项目都在Codeplex或Google Code或Github上,它们都有问题跟踪和讨论系统。我无法在任何地方找到此项目进行公开讨论。**更新。我们在Azure中使用了大约250个同时使用的用户进行了尝试,SQL Azure向我们发送了错误消息,表明物理机器无法接受更多连接,即使我们在允许的连接限制内。我的结论是在Azure中避免这种类型的会话管理。顺便说一句,我们尝试这样做的唯一原因是我们当前的会话状态支持程序Azure Caching有太多的中断。
private void PurgeExpiredSessions()
{
    try
    {
        using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
        {
            foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
            {
                entities.DeleteObject(entity);
            }
            entities.SaveChanges();
            this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
        }
    }
    catch
    {
    }
}