2011-09-06 22 views
6

Quiero lanzar una excepción pero con un mensaje personalizado y persistir stacktrace también. He pasado por varios hilos.Lanzar excepción pero persistir el seguimiento de la pila

catch (Exception ex) 
{ 
throw; // Message is read only but stacktrace persist 
throw ex; // Message is readonly and strack trace also blows .. worst! 
throw new CustomException("My exception");// Message can be overridden but stacktrace lost 
throw new CustomException("My message",ex);// same as above. However if this constructor in exception class calls same constructor of base class then .. see below 
} 

Cuando se utiliza la última appraoch (con el constructor excepción personalizada llamando al constructor de la clase base), la salida en la pantalla de la muerte es algo así como:

**The remote server returned an error: (401) Unauthorized.** 

[WebException: The remote server returned an error: (401) Unauthorized.] 
original stack trace 

[NewException: newMessage] 
New Stack Trace 

Lo bueno es que todo está allí en la pantalla. Pero, en la parte superior, quiero que mi excepción se muestre, es decir, "mensaje nuevo" y no el mensaje original.

Por lo tanto, reconciliando mi pregunta: ¿CÓMO puedo mostrar en la pantalla de la muerte el trazado original de la pila pero con un mensaje de error personalizado?

+1

Es éste un servicio web volviendo la excepción? – Oded

+0

En mi ejemplo, de hecho es una llamada de servicio web. Sin embargo, es inmaterial, ya que la excepción podría haber sido algo como DivisionByZero o sqlException, etc. Idea es permitir que el usuario conozca el rastro original de la pila, pero el desarrollador también puede personalizar el mensaje de excepción predeterminado a uno más útil. – helloworld

+0

No, no es inmaterial. Los marcos del servicio web tienen sus propias ideas sobre excepciones. –

Respuesta

8
throw new CustomException("My message",ex);// same as above (... stacktrace lost) 

Su conclusión en los comentarios es incorrecta en la última. La stacktrace se mantiene en la Excepción interna. Los informes estándar (que incluyen Exception.ToString()) informarán la pila completa. Esto es lo que está viendo cuando obtiene el constructor correcto. (¡Siempre llame al ctor base correcto!).

Pero no reconozco [WebException]. En WCF necesita

<serviceDebug includeExceptionDetailInFaults="true"/> 

Supongo que su entorno web tiene una función similar de supresión de la información de error hacia el cliente.

3

Usando su cuarto enfoque es cómo se hace generalmente y el patrón establecido. No debe confundir el manejo de excepciones (o el aumento) con la forma en que se muestran o registran, o lo que sea.

Si tiene la salida de la excepción (capturada) bajo control, es decir, puede cambiar/escribir el código respectivo, puede simplemente usar el método Exception.ToString(), que imprimiría la excepción externa, incluidas todas las "internas".

Observación: A veces las excepciones internas no se muestran a propósito por una aplicación. Por ejemplo, en WCF (Windows Communication Foundation), la excepción interna ni siquiera se transfiere desde el servidor al cliente a menos que se establezca IncludeExceptionDetails (a través de config, code, ...). Esto generalmente se hace porque la excepción interna se considera un detalle de implementación, que puede proporcionar a un atacante información valiosa para romper su aplicación.

0

¿Qué hay sobre anulando la propiedad de StackTrace?

class CustomException : Exception { 

    public CustomException(string message, Exception inner) : base(message, inner) { 
    } 

    public override string StackTrace { 
     get { 
      if (InnerException != null) { 
       return InnerException.StackTrace; 
      } 
      return base.StackTrace; 
     } 
    } 
} 
+0

gracias! Lo intenté ... Mientras se mostraba la pantalla amarilla de la muerte, la ruptura al devolver InnerException.Stacktrace se llamaba tres veces y cada vez mostraba stacktrace original. Pero es extraño que todavía muestra un nuevo rastro de pila :( – helloworld

+0

@enableDeepak: no sabía que causaría el colapso del universo sobre sí mismo ... lo siento :( –

0

Estoy de acuerdo, la opción 4 es generalmente mejor ...

Sin embargo, durante el desarrollo, me resulta muy útil para poner toda la cláusula catch dentro de un #if (! PRUEBAS), con un fin fuera de ella (para permitir la compilación en modo de depuración):

#if (!DEBUG) 
catch (Exception ex) 
{ 
    // Catch logic for Release mode 
} 
#endif 
finally { } 

Esto hace que la rotura API en el punto donde se produjo el error, en lugar de en el nivel superior.

Simplemente no haga un hábito de #if ...en casi todos los demás casos, utilice

[Conditional("DEBUG")] 

delante de un método en lugar

Cuestiones relacionadas