Adjuntar el depurador .net a la vez que proporciona un registro útil de fallecimiento

StackOverflow https://stackoverflow.com/questions/211622

  •  03-07-2019
  •  | 
  •  

Pregunta

Me gustaría tener algún tipo de mecanismo de excepciones para todos en la raíz de mi código, por lo que cuando una aplicación termina inesperadamente todavía puedo proporcionar un registro útil.

Algo a lo largo de las líneas de

static void Main () {
    if (Debugger.IsAttached)
        RunApp();
    else {
        try {
            RunApp();
        }
        catch (Exception e) {
            LogException(e);
            throw;
        }
    }
 }

Aunque todo esto funciona bien, mi problema es cuando quiero adjuntar el depurador después de que se haya producido la excepción.

Dado que la excepción se escapa al tiempo de ejecución, Windows le pedirá que adjunte Visual Studio, excepto que, como se ha vuelto a generar, todos los locales y los parámetros que se encuentran más arriba en la pila se han perdido.

¿Hay alguna forma de registrar estas excepciones, al mismo tiempo que proporciona una forma de adjuntar el depurador y retener toda la información útil?

¿Fue útil?

Solución

Como ya mencionó Paul Betts, puede que sea mejor que utilice AppDomain.UnhandledException en lugar de un bloque try / catch.

En tu controlador de eventos UnhandledException puedes registrar / mostrar la excepción y luego ofrecer la opción de depurar, por ejemplo. muestre un formulario con los detalles de excepción y los botones para ignorar, depurar o salir.

Si el usuario selecciona la opción de depuración, llame a System.Diagnostics.Debugger.Break () que le permite al usuario adjuntar cualquier depurador que desee con la pila de llamadas completa aún disponible.

Obviamente, puedes deshabilitar esta opción para cualquier compilación que sabes que nunca adjuntarás al depurador.

class Program
{
    static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += ExceptionHandler;

        RunApp();
    }

    static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.ExceptionObject);
        Console.WriteLine("Do you want to Debug?");
        if (Console.ReadLine().StartsWith("y"))
            Debugger.Break();
    }

    static void RunApp()
    {
        throw new Exception();
    }
}

Otros consejos

Horriblemente hacky pero sin enganches de tiempo de ejecución (no conozco ninguno) la única forma de llegar al marco de pila desde donde estás lanzando ...

Todas las excepciones que se sabe que se lanzan al terminal tendrían que tener lo siguiente en su constructor:

#if DEBUG
System.Diagnostics.Debugger.Launch()
#endif

Esto presentaría un diálogo que permite al usuario suministrar el depurador relevante o elegir no y no se producirá ninguna depuración (de cualquier manera, la excepción terminará de construirse y luego se lanzará. Esto obviamente solo funciona en las excepciones cuyo origen controla.

No recomiendo esto, en una compilación de depuración con un depurador adjunto, solo puedes elegir obtener el descanso de 'First Chance' en el lanzamiento de excepciones, que normalmente debería ser suficiente para tus necesidades.

Otra opción es comenzar a generar mini dumps programáticamente en los sitios de lanzamiento de excepciones, tales datos podrían luego ser inspeccionados con una herramienta como windbg pero no interferir demasiado con el comportamiento deseado de la excepción que desenrolla la pila después.

El acto de la excepción que llega a su trampa de captura total es precisamente el desenrollado de la pila que no desea, lo siento. Si te sientes cómodo con C ++ y te apetece, podrías construir una bifurcación mono (pero compleja de acertar) que provocó que todas las excepciones activaran al depurador. Alternativamente, simplemente reconstruya la clase de excepción BCL de mono para hacer lo mismo que se detalla arriba ..

¿Por qué no simplemente lo deja funcionar y luego se registra para recibir los informes de errores de Windows de Microsoft? Consulte http://msdn.microsoft.com/en-us/isv/ bb190483.aspx para los detalles.

Si no quieres hacer eso, puedes usar la función IsDebuggerPresent ( http://msdn.microsoft.com/en-us/library/ms680345.aspx ), y si el resultado es False, en lugar de envolver su código en un try-catch, agregue un controlador de eventos a el evento AppDomain.UnhandledException ( http://msdn.microsoft. com / en-us / library / system.appdomain.unhandledexception.aspx )

No debería simplemente hacer una

Exception e1 = e;
LogException(e);
throw(e1);

dentro de la captura, ¿el truco (al menos puede examinar la excepción externa)?

Si está utilizando estrictamente el modo de depuración para el desarrollo y el modo de lanzamiento para la implementación, podría intentar usar la clase System.Diagnostics.Debugger.

catch (Exception e) {
#if DEBUG
            System.Diagnostics.Debugger.Launch()
#endif
            LogException(e);
            throw;
        }

Puede obtener información de la excepción escribiendo en el registro de seguimiento:

        private static void Main(string[] args)
    {
        try
        {
            // ...
        }
        catch (Exception exception)
        {
            System.Diagnostics.Trace.Write(exception);
            #if DEBUG
            System.Diagnostics.Trace.Write("Waiting 20 seconds for debuggers to attach to process.");
            System.Threading.Thread.Sleep(20000);
            System.Diagnostics.Trace.Write("Continue with process...");
            #endif
            throw;
        }
    }

Utilice DebugView para mostrar el registro de seguimiento. Detener el subproceso durante unos segundos le dará algo de tiempo para adjuntar su depurador para procesar sin perder la excepción original.

Si ninguno de los eventos globales funciona, entonces lo que podría intentar es poner el error catch en cualquier evento que su software maneje. La facilidad de estos depende de la complejidad de sus aplicaciones. Muchas de las aplicaciones escritas con el marco .NET están escritas para manejar eventos, ya sea una aplicación tradicional o una aplicación web. Al colocar los ganchos en los eventos, debería poder conservar la información en la pila que necesita.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top