¿Es aceptable la captura indiscriminada de excepciones (manejo de excepciones de Pokémon)? [duplicar]

14

Normalmente, no anticipo excepciones y, si las obtengo, es algo que no puedo corregir en mi código: problemas de entrada de usuarios o de conectividad con la base de datos.

Pero al menos ocurren errores, quiero informar a mi usuario de que algo salió mal y registrar el error.

Mi manejo de excepciones generalmente se parece a esto:

public JsonResult Create(UserCreateEditViewModel model)
{
    try
    {
        if (!ModelState.IsValid) return Json(new { IsOk = false, Message = "Some of your data was invalid, please try again." });

        var User = new User
        {
            // map UserCreateEditViewModel properties to User properties
        };

        OrtundEntities Db = new OrtundEntities();
        Db.Users.Add(User);
        Db.SaveChanges();

        return Json
    }
    catch(Exception ex)
    {
        // can't correct user data or repair connection
        // issues to the database so just report the error to the user
        return ReportError(ex, "Create User");
    }
}

public JsonResult ReportError(Exception ex, string action)
{
    return Json(new { IsOk = false, Title = action, Message = ex.Message });
}

Soy consciente de que en la mayoría de los casos, se desaconseja manejo de excepciones de Pokémon , pero como no hay nada que pueda hacer con un error, ¿no está bien manejo de excepciones de Pokémon simplemente para informar el error?

    
pregunta Ortund 20.05.2016 - 13:21

5 respuestas

11

Sí. En cualquier momento, las excepciones podrían estar expuestas a usuarios finales o sistemas externos, podría ser una buena idea detectar todas las excepciones posibles, realizar un manejo genérico (como el registro) y emitir un mensaje genérico. Tanto por razones de usabilidad como por razones de seguridad (una excepción puede contener información confidencial).

Pero a menudo este controlador de excepciones de nivel superior no se implementaría como un bloque try..catch real, sino que se manejaría mediante el marco de la aplicación. En un marco web típico, no tendría que escribir try...catch en cada controlador de solicitudes o generador de páginas, sino que registraría el código genérico de control de excepciones en un solo lugar. Si usa ASP.NET MVC, puede usar OnException o similar y ahorrar un montón de manejo de excepciones repetitivo.

Lo importante es que la solicitud o solicitud está aún terminada . Lo que se desalienta es capturar las excepciones de forma indiscriminada y luego continuar con la ejecución como si no hubiera pasado nada. Dado que una excepción inesperada significaría que el estado de la aplicación se ve comprometido de alguna manera desconocida, la ejecución continua solo conducirá a más errores y daños en los datos en la línea, lo que puede ser increíblemente difícil de depurar.

Otra situación (menos común) en la que tiene sentido capturar todo: si tiene una biblioteca no confiable que proporciona un servicio no esencial. Supongamos que tiene una aplicación con una arquitectura de complemento donde terceros pueden proporcionar módulos que se cargarán dinámicamente. Tendría sentido detectar todas las excepciones al llamar a estos complementos, ya que no desea que un complemento defectuoso elimine toda la aplicación.

Incluso los módulos internos podrían tratarse como no confiables. Por ejemplo, he escuchado rumores de que Microsoft trata los subsistemas de Office de esta manera. Si el módulo del verificador de gramática genera una excepción inesperada, es mejor mostrar un cuadro de diálogo con "error inesperado en el verificador de gramática" y continuar sin la verificación, en lugar de que la aplicación finalice.

Tenga en cuenta que esto solo funciona si el módulo puede estar claramente aislado de la aplicación principal, por lo que puede estar seguro de que el error dentro del módulo no corrompe el estado del programa en general. Por ejemplo, necesitaría deshabilitar el complemento o módulo después de la primera excepción inesperada, ya que tiene un estado dañado. Así que esto solo es posible si la aplicación ha sido diseñada explícitamente para permitir este nivel de aislamiento de los módulos en cuestión.

    
respondido por el JacquesB 20.05.2016 - 20:34
3
  

Excepciones de Pokemon ... ¿Alguna vez aceptables?

Nunca digas (N) nunca, pero aquí va. Una conceptualización concisa de las excepciones muestra por qué.

Un bloque try me dice qué situaciones elijo no manejar

Donde las excepciones try , catch y después del hecho manejan son un problema de diseño.

Los bloques try enfocados expresan las preocupaciones del programa. Conexiones no confiables, combinaciones de datos de usuario no definidas, rutas lógicas específicas que son callejones sin salida y así sucesivamente. Todos sabemos que se supone que debemos envolver recursos incontrolables como una llamada a la base de datos o al sistema de archivos, pero eso debe integrarse con el diseño, ser coherente con él.

Claro, no podemos hacer mucho dado una conexión de base de datos fallida, pero capturar y / o lanzar y / o volver a lanzar una excepción sigue siendo una opción, no una necesidad absoluta. Además, puede haber circunstancias de dominio de negocios donde no queremos "recuperar".

Sea lo más informativo posible

Lamentablemente es gracioso que dedique demasiado tiempo a la depuración de excepciones porque no tengo idea de qué estado / datos lo causaron. Simplemente dejar que la aplicación explote es esencialmente lo mismo.

Si sabe exactamente dónde se lanzó o si conoce el tipo de excepción, puede obtener detalles relevantes para transmitir. Por ejemplo, los valores de parámetros utilizados en un SelectCommand si estamos hablando de un SqlException .

El propio tipo de excepción puede ser una expresión del dominio empresarial de la aplicación. Podría crear una o más excepciones específicas de la aplicación que codifiquen, refuercen y expresen callejones sin salida exclusivos de la aplicación. Estas clases pueden tener constructores que aseguran que capturamos datos de usuarios particulares.

Pokémon no tiene sentido

Elimine el try/catch del código anterior y el comportamiento es exactamente el mismo. ES DECIR. intentar todo es lo mismo que intentar nada.

Que se agregó un mensaje "Crear usuario" es superfluo porque conocemos el punto de origen a través del seguimiento de la pila. Y el mensaje agrega un contexto cero para las circunstancias específicas que causaron la excepción.

Limitar try scope == Context

Si estoy ajustando solo la llamada a la base de datos, entonces sé exactamente qué excepciones esperar. Y sé qué datos relevantes cosechar para poner en la propiedad Exception.Data .

Limitar catch scope == Context

La "regla del contexto de la cláusula de captura inversa" de Bob es una antigua máxima que acabo de inventarme. Cuanto más amplio sea el ámbito del try (por una buena razón, suponemos), a continuación, los tipos de excepción más específicos que podríamos desear para catch .

    
respondido por el radarbob 20.05.2016 - 15:58
1

La captura de Exception suele ser una acción incorrecta, sin embargo, hay casos en los que es aceptable y la actividad correcta.

Al escribir API web, es posible que no desee revelar demasiada información sobre las excepciones a sus clientes. También puede haber diseñado en su API un indicador de error para que los clientes puedan usar esto para decidir qué hacer a continuación. En esta situación, capturar todas las excepciones en el límite de su API puede ser lo correcto. Claro, debería estar capturando las excepciones más cerca de donde se lanzan, pero a veces las bibliotecas de terceros no documentan / publican las excepciones que pueden lanzar, por lo que cuando escriba una API debe tener cuidado. El límite de una API también puede ser un lugar excelente para registrar el error, ya que puede diseñar su manejo para que tenga acceso a la solicitud con la que está tratando. Trabajar a partir de una solicitud fallida, combinada con un registro de excepciones puede ser una forma muy efectiva de determinar qué causó una falla.

Ahora, mirando su caso particular, como dije en mi comentario, devolver el mensaje de excepción al cliente parece ser algo incorrecto. La mayoría de los usuarios no podrán interpretar los mensajes de excepción, en el mejor de los casos, podrán informar lo que dice en un informe de error. Cortar el hombre medio y registrar el error en su lugar. Devuelve algún tipo de error genérico al usuario en su lugar.

Además, asegúrate de que lo que esté llamando a tu Create sepa qué hacer cuando reciba IsOk==false porque tratará la llamada como un éxito en lugar de una falla a menos que le indiques lo contrario.

    
respondido por el forsvarir 20.05.2016 - 17:22
1

Sí. Por lo menos, es justificable en el lado del cliente para aplicaciones que sirven a usuarios no técnicos, siempre que esté dando instrucciones significativas para el usuario.

Por ejemplo, "Se produjo un error interno. Vuelva a cargar la página"

Las excepciones siempre deben ser detectadas siempre que se pueda hacer algo significativo para corregir el problema.

    
respondido por el svidgen 20.05.2016 - 20:18
1

No.

Otros han señalado que quizás desee mostrar a los usuarios todas las excepciones en un diálogo agradable, o guardarlas en un registro. Estas no son ideas terriblemente malas.

¿Pero qué sucede cuando la excepción es un StackOverflowException ? Un OutOfMemoryException ? ¡Incluso puedes obtener un ClrException !

En esencia, simplemente no puede atraparlos a todos. Puede intentarlo, e incluso puede proporcionar cierto valor, pero será menos de lo que espera: es probable que el registro de las cosas sea suficiente incluso sin las excepciones en sí.

    
respondido por el Magus 20.05.2016 - 21:45

Lea otras preguntas en las etiquetas