¿Cómo proteger los grupos de aplicaciones de las excepciones de serialización de sesión?
Estamos utilizando un proveedor de sesión fuera de proceso (Poner a escala) para una aplicación ASP.NET y hemos notado quecuando un objeto que no está configurado correctamente para la deserialización llega inadvertidamente a la sesión, lo haráeventualmente hará que todo el proceso finalice.
Reproducir y manejar este escenario es donde se vuelve aún más interesante.
La excepción que termina el proceso se plantea enAnyStaObjectsInSessionState cuya implementación es bastante sencilla:
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;
}
Aquí está el seguimiento de la pila que muestra cómo las excepciones aquí terminan el proceso:
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)
Nos gustaría entender dos cosas:
Cuando haceFireSessionOnEnd fuego para un proveedor fuera de proceso y, lo que es más importante, ¿cómo podemos imitar esto en un entorno de desarrollo que no está bajo carga? He experimentado con tiempos de espera de sesión reducidos (configurados en un minuto), invocando manualmente Abandon () e invocando manualmente GC.Collect (), todo en vano.
¿Podemos atrapar los errores que ocurren en este paso para proteger el grupo de aplicaciones? Las excepciones planteadas aquí se registran conFuente = ASP.NET 2.0.50727.0 y no llegue a los controladores de errores de la aplicación en global.asax. ¿Qué podemos hacer para protegernos de este escenario, incluso después de que se apliquen los controles y equilibrios adecuados a los objetos vinculados a la sesión?
Cualquier idea sería apreciada.