Pergunta

Os erros que ocorrem no fundo de uma camada de acesso de dados ou até mesmo mais acima, (dizer dentro ADO.net operações, por exemplo) raramente faz muito sentido para um usuário final. Simplesmente borbulhando esses erros até a interface do usuário e exibi-los normalmente vai conseguir nada além de frustração para um usuário final.

Eu empregaram recentemente uma técnica básica para relatar erros como este em que eu pegar o erro e, pelo menos, adicionar algum texto amigável para que pelo menos o usuário final entende o que falhou.

Para fazer isso eu estou pegando uma exceção dentro de cada função específica (digamos, por exemplo uma função em uma camada de acesso a dados fetch), em seguida, criar um novo erro com texto usuário amigável sobre a função que falhou e provavelmente causar, mas, em seguida, incorporando a excepção original no novo excepção, tal como o "excepção interior" de novo que excepção.

Este pode então ocorrer a cada camada se necessário, cada consumidor da função de nível inferior acrescentando o seu próprio contexto para a mensagem de erro, de modo que o que atinge a interface do usuário é uma mensagem de erro amigável cada vez mais usuário.

Uma vez que o erro atinge o UI - se necessário - pode, em seguida, percorrer a exceções aninhadas para exibir uma mensagem de erro que em primeiro lugar informa ao usuário que a operação falhou, mas também fornece um pouco de informação técnica sobre o que realmente deu errado .

por exemplo.

"A lista de nomes de clientes a sua solicitada não pode ser exibida. "

"A obtenção da lista de clientes você solicitada falhou devido a um erro com o banco de dados ".

"Houve um erro ao conectar a banco de dados ao recuperar uma lista de clientes "

"Falha de logon do usuário xx"

A minha pergunta é esta: Esta é uma terrivelmente ineficientes (todas essas exceções aninhadas)? Eu suspeito que não é a melhor prática então o que devo fazer para conseguir a mesma coisa - ou devo ser de fato tentando alcançar algo melhor

?
Foi útil?

Solução

É apenas ligeiramente horrível.

Se você está mostrando um erro para o usuário final, o usuário deve ser capaz de agir sobre isso. Em "A lista de nomes de clientes o seu pedido não pôde ser exibido." caso, o usuário só vai pensar "e daí?" Em todos esses casos, apenas exibir uma mensagem "algo de ruim aconteceu". Você não precisa mesmo de capturar essas exceções, quando algo vai mal, deixe algum método global (como Application_Error) segurá-lo e exibir uma mensagem genérica. Quando você ou o usuário pode fazer algo sobre o erro, pegá-lo e fazer a coisa ou notificar o usuário.

Mas você vai querer registrar cada erro que você não tratar.

A propósito, exibindo informações sobre os erros que ocorrem podem render a vulnerabilidades de segurança. Quanto menos os atacantes sabem sobre o seu sistema, a menos provável que eles vão encontrar maneiras de cortá-lo (lembre-se essas mensagens como "erro de sintaxe na instrução SQL: SELECT * dos usuários ONDE username = 'a'; database drp; -' .. ." esperado:.. 'drop' em vez de 'drp' Eles não fazem sites como estes anymore)

Outras dicas

É tecnicamente caro para lançar novas exceções, no entanto eu não vou fazer um grande debate para fora do que uma vez "caro" é relativo - se você está jogando 100 tais exceções um minuto, você provavelmente não vai ver o custo; se você está jogando 1000 tais exceções um segundo, você pode muito bem ver um acerto de desempenho (daí, não realmente vale a pena discutir aqui - o desempenho é a sua chamada).

Eu acho que tem que perguntar por que esta abordagem está sendo usado. É verdade que você pode adicionar informações de exceção significativa em todas nível onde uma exceção pode ser lançada e, se assim for, é também verdade que as informações serão:

  • Algo que você realmente deseja para compartilhar com seu usuário?
  • algo que seu usuário será capaz de interpretar, compreender e uso ?
  • escrito de tal forma que ele não irá interferir com posterior reutilização de componentes de baixo nível, a utilidade de que pode não ser conhecido quando foram escritos?

Eu pergunto sobre o compartilhamento de informações com o usuário, porque, no seu exemplo, sua pilha começa artificiais por informando o usuário que havia um problema de autenticação no banco de dados. Para um hacker em potencial, que é um bom pedaço de informação que expõe algo sobre o que a operação estava fazendo.

Como para a entrega de volta toda uma pilha de exceção costume, eu não acho que é algo que será útil para a maioria dos usuários (honesto). Se eu estou tendo problemas para obter uma lista de nomes de clientes, por exemplo, é que vai me ajudar (como um usuário) para saber que havia um problema com a autenticação do banco de dados? A menos que você estiver usando autenticação integrada, e cada um de seus usuários tem uma conta, ea capacidade de entrar em contato com o administrador do sistema para descobrir por que sua conta não possui privilégios, provavelmente não.

Gostaria de começar por primeiro decidir se há realmente uma diferença semântica entre a exceção Framework lançada ea mensagem de exceção que você gostaria de fornecer para o usuário. Se houver, então vá em frente e usar uma exceção personalizada no nível mais baixo ( 'login falhou' no seu exemplo). Os passos seguintes que, até a apresentação real da exceção, realmente não necessita de quaisquer exceções personalizadas. A exceção que você está interessado já tenha sido gerado (o login falhou) - continuando a envolver essa mensagem em todos os níveis da pilha de chamadas não serve a nenhum propósito real diferente de expor sua pilha de chamadas para seus usuários. Para esses passos "meio", assumindo qualquer try / catch blocos estão no lugar, um 'log e jogar' simples estratégia iria funcionar bem.

Na verdade, porém, essa estratégia tem uma outra potencial falha: ela força sobre o desenvolvedor a responsabilidade de manter o padrão de exceção personalizada que tem sido implementado. Desde que você não pode saber todas as permutações de hierarquia de chamadas ao escrever tipos de baixo nível (seus "clientes" pode até não ter sido escrito ainda), parece improvável que todos os desenvolvedores - ou até mesmo um desenvolvedor - se lembrar de envolver e customize qualquer condição de erro em cada bloco de código.

Em vez de trabalhar em cima de fundo, eu normalmente se preocupar com a exibição de exceções lançadas como no final do processo quanto possível (ou seja, o mais próximo do "top" da pilha de chamadas que possível). Normalmente, eu não tentar substituir quaisquer mensagens em exceções lançadas em níveis baixos de minhas aplicações - particularmente desde que a utilização desses membros de baixo nível tendem a ficar mais e mais abstrata quanto mais profunda a chamada recebe. I tendem a pegar e exceções logar-se a camada de negócios e diminuir, então lidar com exibi-los de forma compreensível na camada de apresentação.

Aqui estão um par de artigos decentes em exceção de manipulação melhores práticas:

http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx

http://aspalliance.com/1119

Eita este prolixo tem ... desculpas antecipadamente.

Sim, as exceções são caros para que haja um custo envolvido na captura e rethrowing ou jogando uma exceção mais útil.

Mas espere um minuto! Se o código de estrutura ou a biblioteca que você está usando lança uma exceção, em seguida, as coisas já estão vindo unstuck. Você tem requisitos não-funcionais para a rapidez com que uma mensagem de erro é propagado seguindo uma exceção? Eu duvido. É realmente um grande negócio? imprevisto algo e 'excepcional' que aconteceu. A principal coisa é apresentar informações sensível, útil para o usuário.

Eu acho que você está no caminho certo com o que você está fazendo.

É claro que é terrivelmente ineficiente. Mas no ponto em que ocorre uma exceção que é suficiente importante para mostrar para o usuário final, você não deve se preocupar com isso.

Onde eu trabalho temos apenas algumas razões para capturar exceções. Nós só fazê-lo quando ...

  1. Nós podemos fazer algo sobre isso -. Por exemplo Sabemos que isso pode acontecer algumas vezes e podemos corrigi-lo em código como acontece (muito raro)

  2. Queremos saber isso acontece e onde (então nós apenas relançar a exceção).

  3. Queremos adicionar uma mensagem amigável para o caso que envolva a exceção original em uma nova excpetion derivado de exceção de aplicativo e adicionar uma mensagem amigável para isso e depois deixá-lo borbulhar inalterada a partir desse ponto.

No seu exemplo nós provavelmente apenas exibir "Ocorreu um erro de início de sessão." anbd deixar por isso mesmo ao registrar o erro real e fornecendo um motivo para o usuário para furar a exceção se eles queriam também. (Talvez um botão no formulário de erro).

  1. Queremos suprimir a exceção completamente e continuar. Escusado será dizer que nós só fazer isso para tipos de exceção esperados e somente quando não há outra maneira de detectar a condição que gera a exceção.

Geralmente, quando você está lidando com exceções, desempenho e eficiência são a menor das suas preocupações. Você deve estar mais preocupado em fazer algo para ajudar o usuário recuperar do problema. Se havia um problema escrevendo um determinado registro no banco de dados, ou rolar as alterações de volta ou pelo menos despejar as informações da linha de modo que o usuário não perdê-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top