2010-06-21 3 views
7

Stiamo utilizzando un Session Provider out-of-process (ScaleOut) per un'applicazione ASP.NET e abbiamo notato che quando un oggetto che non è configurato correttamente per la mancata serializzazione entra inavvertitamente nella sessione sarà alla fine causare l'intero processo per terminare.Come proteggere i pool di applicazioni dalle eccezioni di serializzazione della sessione?

Riprodurre e gestire questo scenario è dove diventa ancora più interessante.

L'eccezione che termina il processo è sollevata in AnyStaObjectsInSessionState la cui realizzazione è abbastanza semplice:

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; 
} 

Ecco la traccia dello stack che mostra come le eccezioni qui terminano il processo:

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) 

Noi vorrei capire due cose:

  1. Quando fa il fuoco FireSessionOnEnd per un fornitore out-of-process e, cosa più importante, come possiamo imitare questo in un ambiente di sviluppo che non è sotto carico? Ho sperimentato un timeout di sessione ridotto (impostato su un minuto), richiamando manualmente Abandon() e invocando manualmente GC.Collect(), tutto senza alcun risultato.

  2. È possibile intercettare gli errori che si verificano in questo passaggio per proteggere il pool di applicazioni? Le eccezioni qui riportate sono registrate con Origine = ASP.NET 2.0.50727.0 e non raggiungono i gestori di errori dell'applicazione in global.asax. Che cosa possiamo fare per evitare questo scenario, anche dopo i controlli appropriati, i saldi & vengono applicati agli oggetti legati alla sessione?

Eventuali approfondimenti sarebbero apprezzati.

+1

Forse dovrebbero risolvere il loro codice per non consentire un'eccezione serialziation per arrestare l'AppDomain. Solo un pensiero. –

+0

È una buona idea, e penso che siano d'accordo; è uno scenario estremamente raro ma che va comunque protetto. – Nariman

+0

@ John: Sembra che stia usando Lucene.net. Anche se è un'app di terze parti, AFAIK, il suo open source e dovrebbe contrassegnare la classe "Serializable' – ram

risposta

3

Siamo stati in grado di risolvere il problema con l'aiuto di supporto tecnico SOSS - erano estremamente utile - ecco il dettagli:

  • su sessione di scadenza, SOSS genera un evento di scadenza nelle sue librerie client, che a loro volta sono responsabili per la cottura Session_End in Global.asax (NB: bilancia il carico ScaleOut eventi di scadenza attraverso i clienti, in modo che il web server che c la sessione potrebbe non ricevere necessariamente l'evento di scadenza - questo è fondamentale per provare a riprodurre questi problemi).
  • Poiché ciò accade al di fuori del contesto di una richiesta, l'eccezione non è gestita e uccide il pool di app;
  • È uno scenario estremamente insolito, ma che sarà comunque affrontato nelle prossime versioni di manutenzione;
  • I rimedi sono i seguenti:

    1. Fissare il System.Exception tipo -derived (che è serializzabile ma non unserializable);

    2. Rimuovere Session_End eventi in Global.asax o disattivare le eventi di scadenza (max_event_retries impostato a 0 in soss_params.txt);

    3. In questi scenari, è probabile che l'utente incontra un SerializationException su uno dei loro richieste, il che significa che raggiunge Application_Error; qui è possibile cancellare le chiavi di sessione (è necessario cancellare tutte le ) o abbandonare la sessione a titolo definitivo;

    4. Iscriviti a AppDomain.UnhandledException essere notificata eccezioni non gestite, dovrebbero verificarsi (senza ricorrere qui, solo la registrazione); possono anche essere disattivati ​​tramite legacyUnhandledExceptionPolicy (non consigliato);

1

È possibile intercettare gli errori che si verificano in questo passaggio per proteggere il pool di applicazioni? Le eccezioni qui registrate sono registrate con Origine = ASP.NET 2.0.50727.0 e non raggiungere i gestori di errori dell'applicazione in global.asax. Cosa possiamo fare per proteggere da questo scenario, anche dopo i controlli appropriati. & I saldi vengono applicati agli oggetti legati alla sessione?

Non so se this funzionerà, ma si può dare un colpo

+0

Grazie, ma questo non fa davvero da guardia allo scenario, ti lascia semplicemente loggare. Ecco un modo rapido per riprodurre: http://www.brianlow.com/index.php/2007/01/11/catching-unhandled-aspnet-exceptions/. Il thread in background * deve * catturare l'eccezione o la nave va giù. – Nariman

0

Ho fissato questo semplicemente rimuovendo completamente i metodi SessionEnd. Non è sufficiente rimuovere il contenuto dei metodi mentre Asp.net cerca l'esistenza del metodo usando reflection e quindi esegue il codice incriminato.

Problemi correlati