2010-07-14 6 views
12

Sto cercando informazioni su come strumentare una piattaforma runtime per esporre il tipo di origine di un errore di deserializzazione binaria Microsoft .Net.. Deserializzazione binaria netta Rilevazione guasti/analisi forense per piattaforma runtime

Quando si utilizza BinaryFormatter.Deserialize(StreamingContextStates.CrossMachine) e uno dei tipi non esiste nei file binari correnti; invece di generare un errore, .Net inserisce l'oggetto [TypeLoadExceptionHolder]. In particolare per le collezioni, questo non causa alcun problema immediato.

Successivamente quando la raccolta viene serializzata per la trasmissione tra i livelli dell'applicazione; la piattaforma riceve un 'errore di serializzazione' perché [TypeLoadExceptionHolder] non può essere serializzato. Quindi l'errore risultante è inutile per fornire effettivamente indizi sul tipo di origine che ha causato il problema. Ora la caccia (time suck) è attiva per vedere quale sviluppatore (di centinaia) ha aggiunto un nuovo tipo a una piattaforma di milioni di righe.

Questo problema si verifica con una certa frequenza a causa del flusso di serializzazione utilizzato per supportare la piattaforma sessioncache. Il codice viene distribuito abbastanza spesso e in modo incrementale. Le richieste di pagine del cliente possono rimbalzare tra vecchie e nuove versioni del codebase durante la finestra di distribuzione. L'introduzione incurante di un nuovo tipo farà esplodere le richieste di pagina sulla vecchia versione.

Qualsiasi idea sull'errore/trap ricco di runtime sarebbe apprezzata.


(SerializationException) 
Type 'System.Runtime.Serialization.TypeLoadExceptionHolder' in Assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable. 
- at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) 
- at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
- at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) 
- at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) 
- at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) 

risposta

4

Beh, un approccio che si potrebbe prendere è quella di utilizzare un costume SerializationBinder che sostituisce BindToType e controlla il nome del tipo durante la deserializzazione.

A seconda di cosa si desidera realizzare, quando si identifica un tipo sconosciuto si potrebbe o:

  • sollevare un'eccezione (pessimistica): Prendere il problema nella fase iniziale e può facilmente l'identità del tipo con un messaggio personalizzato o un'eccezione.

  • Registra il nome del tipo (ottimistico): se esistono scenari in cui i tipi sconosciuti sono corretti, la registrazione fornirebbe i dettagli necessari per diagnosticare le eccezioni se si verificano successivamente durante la serializzazione.

Si potrebbe anche scegliere un approccio diverso a seconda delle caratteristiche del nome del tipo (vale a dire se il tipo sembra essere parte della vostra applicazione o parte di una libreria di 3a parte).

L'istanza TypeLoadExceptionHolder creata durante la deserializzazione contiene un membro non pubblico TypeName che contiene il nome del tipo che non è stato possibile risolvere. Tuttavia, l'istanza non è disponibile dal SerializationException che si incontra in seguito, e anche così, il valore sarebbe disponibile solo tramite riflessione in contesti fidati.

public class CustomSerializationBinder : SerializationBinder 
{ 
    public override Type BindToType(string assemblyName, string typeName) 
    { 
     Type t = Type.GetType(string.Concat(typeName, ", ", assemblyName)); 

     if (t == null) 
     { 
      throw new SerializationException(string.Format("Type {0} from assembly {1} could not be bound.", typeName, assemblyName)); 
     } 

     return t; 
    } 

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName) 
    { 
     base.BindToName(serializedType, out assemblyName, out typeName); 
    } 
} 

... 

BinaryFormatter.Binder = new CustomSerializationBinder();