5

我们在 ASP.NET Web 应用程序中得到随机 System.NullReferenceException。我们正在使用 inproc 会话状态。堆栈跟踪:

System.NullReferenceException: Object reference not set to an instance of an object.
at System.Collections.Specialized.NameObjectCollectionBase.BaseRemove(String name)
at System.Web.SessionState.SessionStateItemCollection.Remove(String name)
at System.Web.SessionState.HttpSessionStateContainer.Remove(String name)
at System.Web.UI.SessionPageStatePersister.Save()
at System.Web.UI.Page.SaveAllState()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

问题似乎来自我们已经像这样覆盖的 Page.PageStatePersister 属性。

protected override PageStatePersister PageStatePersister {
  get {
    return new SessionPageStatePersister(Page); 
  }
}

Reflector 显示 SessionPageStatePersister 在内部调用了 Session.Remove。

当直接在 Page 上调用 Session.Remove 时,我们会得到类似的随机 NullReferenceException。相关堆栈跟踪:

---> System.NullReferenceException: Object reference not set to an instance of an object.
at System.Collections.Specialized.NameObjectCollectionBase.BaseRemove(String name)
at System.Web.SessionState.SessionStateItemCollection.Remove(String name)
at System.Web.SessionState.HttpSessionStateContainer.Remove(String name)
at System.Web.SessionState.HttpSessionState.Remove(String name)
at PERH.WebFramework.Bases.PageBase.OnPreInit(EventArgs e) in 

任何想法,什么可能导致这些异常?

环境:

IIS6、Windows Server 2003 64 位、.net Framework 3.5

4

1 回答 1

2

当同时处理同一用户(来自同一会话 ID)的请求时,可能会出现此问题。

这是因为System.Web.SessionState.SessionStateItemCollection在删除条目时不检查条目是否为空。

在该System.Web.SessionState.SessionStateItemCollection.Remove(string name)方法中,锁定是在私有集合上设置的,_serializedItems因此Remove操作是线程安全的。然而,这个私有集合在添加操作期间不会被锁定。考虑到它的_serializedItems行为类似于一个调整大小的数组(当条目数 >= 其容量的 1/2 时,容量会增加一倍,并且新条目用空值填充)并发添加可能会导致空值保留在集合中间的情况。条目只会从 [0; 条目计数]_serializedItems集合的范围。删除条目Key时,无需检查空值即可访问其属性。因此,如果集合中间的NullReferenceException条目被删除,则获取强制转换。

默认情况下,所有具有相同会话 ID 的请求都会按顺序处理,除非System.Web.Configuration.PagesSection.EnableSessionState明确设置为ReadOnly. 在这种情况下,任何涉及将值添加到System.Web.SessionState.HttpSessionState(内部使用System.Web.SessionState.HttpSessionStateContainer而内部使用System.Web.SessionState.SessionStateItemCollection)的操作都应正确锁定以确保线程安全。

于 2018-03-22T21:58:34.053 回答