2011-10-19 8 views
12

Problema:E 'possibile in .Net catturare tutte le eccezioni non gestite da qualsiasi metodo in una classe prima che sia passato allo stack delle chiamate?

vorrei cogliere eventuali eccezioni da qualsiasi metodo in una classe in modo che io possa registrare i dati specifici della classe di eccezione per la registrazione prima di essere superato lo stack. So che posso mettere un try-catch in ogni metodo della classe, ma ci sono molti metodi e sembra che ci dovrebbe essere un modo più efficiente.

Esempio di quello che sto facendo attualmente:

public class ClassA 
{ 
    private int x; 
    private int y; 

    public void Method1() 
    { 
     try 
     { 
      //Some code 
     } 
     catch(Exception ex) 
     { 
      ex.Data.Add("x", x); 
      ex.Data.Add("y", y); 
      throw; 
     } 
    } 

    public void Method2() 
    { 
     try 
     { 
      //Some code 
     } 
     catch (Exception ex) 
     { 
      ex.Data.Add("x", x); 
      ex.Data.Add("y", y); 
      throw; 
     } 
    } 
} 

esempio di quello che vorrei fare:

public class ClassB : IUnhandledErrorHandler 
{ 
    private int x; 
    private int y; 

    public void Method1() 
    { 
     //Some code 
    } 

    public void Method2() 
    { 
     //Some code 
    } 

    void IUnhandledErrorHandler.OnError(Exception ex) 
    { 
     ex.Data.Add("x", x); 
     ex.Data.Add("y", y); 
     throw; 
    } 
} 

public interface IUnhandledErrorHandler 
{ 
    void OnError(Exception ex); 
} 

Nota: Questa classe è un servizio in un progetto WCF e implementa un ServiceContract. Ho provato ad aggiungere un ErrorHandler al ChannelDispatcher del servizio. Tuttavia, quando l'errore raggiunge ErrorHandler, è già oltre l'ambito della classe in cui si è verificato l'errore, quindi non posso accedere ai dettagli della classe.

Soluzione:

public class ClassC 
{ 
    public ClassC() 
    { 
     AppDomain.CurrentDomain.FirstChanceException += OnError; 
    } 

    private int x; 
    private int y; 

    public void Method1() 
    { 
     //Some code 
    } 

    public void Method2() 
    { 
     //Some code 
    } 

    private void OnError(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e) 
    { 
     e.Exception.Data["x"] = x; 
     e.Exception.Data["y"] = y; 
    } 
} 
+0

È solo per il debug? Vuoi inviare le eccezioni al client o semplicemente tenerle su server? –

+0

È per il debug/logging sul lato server. – KowalskiTom

+4

Non si dovrebbe mai usare "throw ex;". Questo fa sembrare che l'eccezione originariamente venisse dalla posizione di "throw ex;". –

risposta

14

Se si esegue il .NET 4, è possibile utilizzare l'evento FirstChanceException dal dominio di applicazione.

+0

Questo sembra promettente. Cercherò di implementarlo per vedere se è una soluzione praticabile. – KowalskiTom

+0

Che funziona, grazie – KowalskiTom

+0

Buono :-) Felice di sapere che l'hai raggiunto :-) – Seb

0

è possibile eseguire questa ereditando da System.ContextBoundObject. Non è bello come speri tu, e credo che ci sia probabilmente un sovraccarico significativo associato, ma per quanto ne so è l'unico modo per fare ciò che descrivi.

Come richiesto qui è un'ulteriore elaborazione ... come accennato non è carina, ma qui è necessaria una minima implementazione per far funzionare questo. Il metodo principale di interesse è il metodo AOPSink.SyncProcessMessage. Viene chiamato prima di qualsiasi metodo su un oggetto 'Test' e la chiamata a NextSink.SyncProcessMessage (msg) è ciò che effettivamente richiama il metodo chiamato in origine. È possibile esaminare (e modificare) quale metodo è stato chiamato ed i parametri passati giocando con il parametro IMessage passato a SyncProcessMessage ed è possibile ispezionare/modificare il valore di ritorno (o Eccezione lanciata) giocando con l'IMessage restituito da NextSink.SyncProcessMessage. Esiste un sovraccarico significativo delle prestazioni per questa funzionalità, quindi non lo consiglierei per gli oggetti ad alto traffico al di fuori degli scopi di debug.

[AOP] 
class Test : ContextBoundObject 
{  
    public void TestMethod()  
    { 
     throw new Exception(); 
    }  
} 

[AttributeUsage(AttributeTargets.Class)] 
public class AOPAttribute : ContextAttribute 
{ 
    public AOPAttribute() : base("AOPAttribute") { } 
    public override void GetPropertiesForNewContext(IConstructionCallMessage ctor) 
    { 
     ctor.ContextProperties.Add(new AOPProperty()); 
    } 
    public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg) 
    { 
     return false; 
    } 
} 

public class AOPProperty : IContextProperty, IContributeServerContextSink 
{ 
    public IMessageSink GetServerContextSink(IMessageSink nextSink) 
    { 
     return new AOPSink(nextSink); 
    } 
    public string Name { get { return "AOP"; } } 
    public bool IsNewContextOK(Context ctx) { return true; } 
    public void Freeze(Context ctx) { } 
} 

public class AOPSink : IMessageSink 
{ 
    public AOPSink(IMessageSink nextSink) { this.NextSink = nextSink; } 
    public IMessageSink NextSink { get; private set; } 
    public IMessage SyncProcessMessage(IMessage msg) 
    { 
     // inspect method+params by playing with 'msg' here 
     IMessage m = NextSink.SyncProcessMessage(msg); 
     // inspect returnval/exception by playing with 'm' here 
     return m; 
    } 
    public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) 
    { 
     throw new NotSupportedException(); 
    } 
} 
+0

Potete per favore elaborare? Non credo che l'oggetto abbia alcun modo di affrontare la domanda dell'OP. – CodeNaked

+0

Potrebbe essere un sovraccarico, poiché verrà utilizzato in produzione per la registrazione. Inoltre, è possibile accedere ai campi della classe da cui è stato generato l'errore? – KowalskiTom

+0

Certo, potresti incapsulare tutto il materiale di Context + Sink in una classe base con un metodo astratto "OnError" che verrebbe chiamato da SyncProcessMessage .... così potrai quindi gestire l'eccezione direttamente nella classe che lo ha lanciato (proprio come il tuo esempio 'cosa vorrei fare') – redec

Problemi correlati