如何保护应用程序池免受会话序列化异常的影响?

时间:2010-06-21 15:59:34

标签: asp.net session serialization httpmodule restart

我们正在为ASP.NET应用程序使用进程外会话提供程序( ScaleOut ),我们注意到对象不正确时反序列化的设置无意中进入会话,它将最终导致整个进程终止

重现和处理这种情况会让它变得更有趣。

终止进程的异常在 AnyStaObjectsInSessionState 中引发,其实现非常简单:

internal static bool AnyStaObjectsInSessionState(HttpSessionState session)
{
    if (session != null)
    {
        int count = session.Count;
        for (int i = 0; i < count; i++)
        {
            object obj2 = session[i];
            if (((obj2 != null) && (obj2.GetType().FullName == "System.__ComObject"))
                && (UnsafeNativeMethods.AspCompatIsApartmentComponent(obj2) != 0))
            {
                return true;
            }
        }
    }
    return false;
}

这是堆栈跟踪,显示了异常如何终止进程:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/1/ROOT

Process ID: 4208

Exception: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Web.Util.AltSerialization.ReadValueFromStream(BinaryReader reader)
   at System.Web.SessionState.SessionStateItemCollection.ReadValueFromStreamWithAssert()
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(String name, Boolean check)
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(Int32 index)
   at System.Web.SessionState.SessionStateItemCollection.get_Item(Int32 index)
   at System.Web.SessionState.HttpSessionStateContainer.get_Item(Int32 index)
   at System.Web.Util.AspCompatApplicationStep.AnyStaObjectsInSessionState(HttpSessionState session)
   at System.Web.HttpApplicationFactory.FireSessionOnEnd(HttpSessionState session, Object eventSource, EventArgs eventArgs)
   at System.Web.SessionState.SessionOnEndTargetWorkItem.RaiseOnEndCallback()
   at System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

InnerException: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.GetConstructor(Type t, Type[] ctorParams)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)

我们想了解两件事:

  1. FireSessionOnEnd 何时为进程外提供程序触发,更重要的是,我们如何在未加载的开发环境中模仿它?我已经尝试降低会话超时(设置为一分钟),手动调用Abandon(),并手动调用GC.Collect(),但都无济于事。

  2. 我们是否可以捕获此步骤中发生的错误以保护应用池?此处引发的异常将使用 Source = ASP.NET 2.0.50727.0 进行记录,并且不会访问global.asax中的应用程序错误处理程序。即使经过适当的检查后,我们还能做些什么来防范这种情况?余额是否应用于会话绑定对象?

  3. 任何见解都将不胜感激。

3 个答案:

答案 0 :(得分:3)

我们能够在SOSS技术支持的帮助下解决这个问题 - 它们非常有用 - 以下是详细信息:

  • 会话到期后,SOSS会在其客户端库中引发过期事件,而后者又负责在Global.asax中触发Session_End( NB: ScaleOut负载均衡客户端的过期事件,因此网络创建会话的服务器可能无法获得其到期事件 - 这对于尝试重现这些问题至关重要)。
  • 因为这发生在请求的上下文之外,所以异常未处理并杀死应用程序池;
  • 这是一个非常罕见的情况,但他们将在即将发布的维护版本中解决这个问题;
  • 补救措施如下:

    1. 修复 System.Exception - 派生类型(可序列化但不可序列化);

    2. 删除Session_End Global.asax中的事件或禁用 到期事件( max_event_retries 在soss_params.txt中设置为0;

    3. 在这些情况下,很可能是 用户遇到一个 其中一个上的 SerializationException 他们的要求,意味着它到达 的的Application_Error ;在这里你可以清楚 会话密钥(必须清除所有 他们)或放弃会议 彻底;

    4. 订阅 AppDomain.UnhandledException 通知未处理的例外, 它们应该发生(这里没有追索权, 只记录);他们也可以 残疾人通过 legacyUnhandledExceptionPolicy (不是 推荐的);

答案 1 :(得分:1)

  

我们可以捕获此时发生的错误吗?   一步保护应用程序池?该   此处提出的异常记录为w /   Source = ASP.NET 2.0.50727.0并没有   到达应用程序错误处理程序   在global.asax中。我们能做些什么?   甚至可以防范这种情况   经过适当的检查和结余   应用于会话绑定对象?

我不知道this是否可行,但你可以试一试

答案 2 :(得分:0)

我通过简单地完全删除SessionEnd方法来解决这个问题。当Asp.net使用反射搜索方法的存在然后运行有问题的代码时,删除方法的内容是不够的。