2012-02-02 14 views
6

Deseo escribir un atributo para una función (o clase) que capture cualquier excepción lanzada y establezca su propiedad StackTrace en string.Empty. ¿Cómo puedo hacer esto?¿Cómo escribir el atributo que detecta excepciones y elimina stacktrace?

EDIT:

Si no puedo lograr esto en la llanura C#, ¿cómo puedo hacer esto en C# con PostSharp?

+1

Curioso: ¿por qué quieres hacer esto? –

+1

Consulte mi respuesta a continuación, aunque me gustaría desalentar hacer esto. Las excepciones existen por una razón, y eso es para ayudar a la eliminación de errores cuando ocurren. Al eliminar el seguimiento de la pila, está efectivamente ocultando el origen del error, que no encontrará si no está depurando.Si por alguna razón te preocupa la privacidad, puedes intentar ofuscar o encriptar la pila (usando el mismo método descrito en la respuesta), para poder descifrarla luego, por ejemplo, desde un archivo de registro. –

+0

Esto es también lo que necesito, y la razón es porque tengo que pasar un objeto Exception a un servicio web, pero por alguna razón no puedo hacer que el servicio lo acepte. Así que podría simplemente pasar el mensaje y StackTrace, luego volver a crear la excepción del servidor. – ganders

Respuesta

3
[Serializable] 
public class MyAspect: OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     throw new MyCustomException(args.Exception); 
    } 
} 


public class MyCustomException : Exception 
{ 
    public override string StackTrace 
    { 
     get 
     { 
      //return new StackTrace(10).ToString(); //Skip frames 
      return string.Empty; //Return empty string 
     } 
    } 
} 

Realmente tiene que lanzar una NUEVA excepción. El ejemplo de @Ani simplemente volverá a lanzar la excepción ya lanzada con la misma traza de pila (es lo mismo debido a cómo llegaste al aspecto). Lanzar una nueva excepción "cambiará" el seguimiento de la pila pero no lo borrará. Si desea borrarlo, deberá lanzar su propia clase que anule la propiedad de seguimiento de la pila. pasar la excepción anterior a la nueva excepción hará que la excepción anterior sea la excepción interna (si lo desea)

Puede lograr esto con y sin PostSharp. La clave es su clase de excepción personalizada.

Dado el siguiente código

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      Test1(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
     } 

     Console.ReadKey(); 
    } 

    private static void Test1() 
    { 
     try 
     { 
      Test2(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
      throw e; 
     } 
    } 

    private static void Test2() 
    { 
     try 
     { 
      Test3(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
      throw; 
     } 
    } 

    [MyAspect] 
    private static void Test3() 
    { 
     throw new InvalidOperationException(); 
    } 
} 

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     throw args.Exception; 
    } 
} 

la salida es

en ConsoleApplication5.MyAspect.OnException (MethodExecutionArgs args) en C: \ T est \ Program.cs: línea 69 en ConsoleApplication5.Program.Test3() en C: \ Test \ Program.cs: línea 59
en ConsoleApplication5.Program.Test2() en C: \ Test \ Program.cs: línea 47

en ConsoleApplication5.MyAspect.OnException (MethodExecutionArgs args) en C: \ T est \ Program.cs: línea 69 en ConsoleApplication5.Program.Test3() en C: \ Test \ Program.cs: Línea 59
en ConsoleApplication5.Program.Test2() en C: \ Test \ Program.cs: línea 52
en ConsoleApplication5.Program.Test1() en C: \ Test \ Program.cs: línea 34

en ConsoleApplication5.Program .Test1() en C: \ Test \ Program.cs: línea 39 en ConsoleApplication5.Program.Main (String [] args) en C: \ Test \ Program.cs: línea 19

+1

¿Hay alguna manera de hacerlo sin una clase personalizada? Por ejemplo, si quisiera eliminar el rastro de la pila de una 'System.Exception' que se lanza? – cm007

+0

Siempre puede usar la reflexión, pero realmente esto no es algo que quiera hacer en producción. Espero que sea académico o solo para pruebas. Ver @hmemcpy respuesta. –

+0

En su método Test1(), ¿por qué está haciendo "tirar e"? en lugar de "arrojar"; – ganders

3

El seguimiento de pila original de la excepción se almacena en un campo en la clase Exception. Si desea eliminarlo sin crear su propio tipo de excepción, puede eliminarlo a través de la reflexión de esta manera:

[Serializable] 
public sealed class NoStackTraceException : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     RemoveStackTrace(args.Exception); 
    } 

    private void RemoveStackTrace(Exception exception) 
    { 
     FieldInfo stackTraceField = typeof(Exception).GetField("_stackTrace", 
      BindingFlags.NonPublic | BindingFlags.Instance); 
     if (stackTraceField != null) 
     { 
      // sets the value of _stackTrace to null 
      stackTraceField.SetValue(exception, null); 
     } 
    } 
} 

Su excepción contendrá no más el seguimiento de la pila.

Editar Por supuesto que puede lograr lo mismo sin PostSharp también, solo hágalo en el bloque catch.

Cuestiones relacionadas