Browse Source

translate docs/pt-BR/Exception-Handling.md

pull/19708/head
Tiago Viana 2 years ago
parent
commit
a80c481a37
  1. 343
      docs/pt-BR/Exception-Handling.md

343
docs/pt-BR/Exception-Handling.md

@ -0,0 +1,343 @@
# Tratamento de Exceções
O ABP fornece uma infraestrutura integrada e oferece um modelo padrão para lidar com exceções.
* **Lida automaticamente com todas as exceções** e envia uma **mensagem de erro formatada padrão** para o cliente em uma solicitação de API/AJAX.
* Oculta automaticamente os **erros internos de infraestrutura** e retorna uma mensagem de erro padrão.
* Fornece uma maneira fácil e configurável de **localizar** mensagens de exceção.
* Mapeia automaticamente exceções padrão para **códigos de status HTTP** e fornece uma opção configurável para mapear exceções personalizadas.
## Tratamento Automático de Exceções
O `AbpExceptionFilter` lida com uma exceção se **qualquer uma das seguintes condições** forem atendidas:
* A exceção é lançada por uma **ação do controlador** que retorna um **resultado de objeto** (não um resultado de visualização).
* A solicitação é uma solicitação AJAX (o valor do cabeçalho HTTP `X-Requested-With` é `XMLHttpRequest`).
* O cliente aceita explicitamente o tipo de conteúdo `application/json` (por meio do cabeçalho HTTP `accept`).
Se a exceção for tratada, ela é automaticamente **registrada** e uma **mensagem JSON formatada** é retornada ao cliente.
### Formato da Mensagem de Erro
A mensagem de erro é uma instância da classe `RemoteServiceErrorResponse`. O JSON de erro mais simples tem uma propriedade **message** conforme mostrado abaixo:
````json
{
"error": {
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem"
}
}
````
Existem **campos opcionais** que podem ser preenchidos com base na exceção que ocorreu.
##### Código de Erro
O **código de erro** é um valor de string opcional e único para a exceção. A exceção lançada deve implementar a interface `IHasErrorCode` para preencher este campo. Exemplo de valor JSON:
````json
{
"error": {
"code": "App:010042",
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem"
}
}
````
O código de erro também pode ser usado para localizar a exceção e personalizar o código de status HTTP (consulte as seções relacionadas abaixo).
##### Detalhes do Erro
Os **detalhes do erro** são um campo opcional da mensagem de erro JSON. A exceção lançada deve implementar a interface `IHasErrorDetails` para preencher este campo. Exemplo de valor JSON:
```json
{
"error": {
"code": "App:010042",
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem",
"details": "Informações mais detalhadas sobre o erro..."
}
}
```
##### Erros de Validação
**validationErrors** é um campo padrão que é preenchido se a exceção lançada implementar a interface `IHasValidationErrors`.
````json
{
"error": {
"code": "App:010046",
"message": "Sua solicitação não é válida, corrija e tente novamente!",
"validationErrors": [{
"message": "O nome de usuário deve ter no mínimo 3 caracteres.",
"members": ["userName"]
},
{
"message": "A senha é obrigatória",
"members": ["password"]
}]
}
}
````
`AbpValidationException` implementa a interface `IHasValidationErrors` e é automaticamente lançada pelo framework quando a entrada de uma solicitação não é válida. Portanto, geralmente você não precisa lidar com erros de validação, a menos que tenha lógica de validação altamente personalizada.
### Registro
As exceções capturadas são automaticamente registradas.
#### Nível de Registro
As exceções são registradas com o nível `Error` por padrão. O nível de log pode ser determinado pela exceção se ela implementar a interface `IHasLogLevel`. Exemplo:
````C#
public class MinhaExcecao : Exception, IHasLogLevel
{
public LogLevel LogLevel { get; set; } = LogLevel.Warning;
//...
}
````
#### Exceções de Registro Próprio
Alguns tipos de exceção podem precisar escrever logs adicionais. Eles podem implementar a interface `IExceptionWithSelfLogging` se necessário. Exemplo:
````C#
public class MinhaExcecao : Exception, IExceptionWithSelfLogging
{
public void Log(ILogger logger)
{
//...log informações adicionais
}
}
````
> Os métodos de extensão `ILogger.LogException` são usados para escrever logs de exceção. Você pode usar o mesmo método de extensão quando necessário.
## Exceções de Negócios
A maioria de suas próprias exceções será exceções de negócios. A interface `IBusinessException` é usada para marcar uma exceção como uma exceção de negócios.
`BusinessException` implementa a interface `IBusinessException` além das interfaces `IHasErrorCode`, `IHasErrorDetails` e `IHasLogLevel`. O nível de log padrão é `Warning`.
Normalmente, você tem um código de erro relacionado a uma exceção de negócios específica. Por exemplo:
````C#
throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer);
````
`QaErrorCodes.CanNotVoteYourOwnAnswer` é apenas uma `const string`. O seguinte formato de código de erro é recomendado:
````
<namespace-do-código>:<código-de-erro>
````
**namespace-do-código** é um **valor único** específico para o seu módulo/aplicação. Exemplo:
````
Volo.Qa:010002
````
`Volo.Qa` é o namespace do código aqui. O namespace do código será então usado ao **localizar** mensagens de exceção.
* Você pode **lançar diretamente** uma `BusinessException` ou **derivar** seus próprios tipos de exceção dela quando necessário.
* Todas as propriedades são opcionais para a classe `BusinessException`. Mas geralmente você define a propriedade `ErrorCode` ou `Message`.
## Localização de Exceções
Um problema ao lançar exceções é como localizar mensagens de erro ao enviá-las para o cliente. O ABP oferece dois modelos e suas variantes.
### Exceção Amigável ao Usuário
Se uma exceção implementa a interface `IUserFriendlyException`, então o ABP não altera suas propriedades `Message` e `Details` e a envia diretamente para o cliente.
A classe `UserFriendlyException` é a implementação integrada da interface `IUserFriendlyException`. Exemplo de uso:
````C#
throw new UserFriendlyException(
"O nome de usuário deve ser único!"
);
````
Dessa forma, **não há necessidade de localização**. Se você deseja localizar a mensagem, pode injetar e usar o **localizador de strings padrão** (consulte o [documento de localização](Localization.md)). Exemplo:
````C#
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"]);
````
Em seguida, defina no **recurso de localização** para cada idioma. Exemplo:
````json
{
"culture": "pt",
"texts": {
"UserNameShouldBeUniqueMessage": "O nome de usuário deve ser único!"
}
}
````
O localizador de strings já suporta **mensagens parametrizadas**. Por exemplo:
````C#
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage", "john"]);
````
Em seguida, o texto de localização pode ser:
````json
"UserNameShouldBeUniqueMessage": "O nome de usuário deve ser único! '{0}' já está em uso!"
````
* A interface `IUserFriendlyException` é derivada da `IBusinessException` e a classe `UserFriendlyException` é derivada da classe `BusinessException`.
### Usando Códigos de Erro
`UserFriendlyException` é bom, mas tem alguns problemas em usos avançados:
* Requer que você **injete o localizador de strings** em todos os lugares e sempre o use ao lançar exceções.
* No entanto, em alguns casos, pode **não ser possível** injetar o localizador de strings (em um contexto estático ou em um método de entidade).
Em vez de localizar a mensagem ao lançar a exceção, você pode separar o processo usando **códigos de erro**.
Primeiro, defina o mapeamento do **namespace-do-código** para o **recurso de localização** na configuração do módulo:
````C#
services.Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Qa", typeof(QaResource));
});
````
Então, qualquer uma das exceções com o namespace `Volo.Qa` será localizada usando seu recurso de localização fornecido. O recurso de localização deve sempre ter uma entrada com a chave do código de erro. Exemplo:
````json
{
"culture": "pt",
"texts": {
"Volo.Qa:010002": "Você não pode votar em sua própria resposta!"
}
}
````
Então uma exceção de negócios pode ser lançada com o código de erro:
````C#
throw new BusinessException(QaDomainErrorCodes.CanNotVoteYourOwnAnswer);
````
* Lançar qualquer exceção que implemente a interface `IHasErrorCode` se comporta da mesma maneira. Portanto, a abordagem de localização de código de erro não é exclusiva para a classe `BusinessException`.
* Não é necessário definir uma string localizada para uma mensagem de erro. Se não estiver definido, o ABP envia a mensagem de erro padrão para o cliente. Ele não usa a propriedade `Message` da exceção! se você deseja isso, use a `UserFriendlyException` (ou use um tipo de exceção que implemente a interface `IUserFriendlyException`).
#### Usando Parâmetros de Mensagem
Se você tiver uma mensagem de erro parametrizada, poderá defini-la com a propriedade `Data` da exceção. Por exemplo:
````C#
throw new BusinessException("App:010046")
{
Data =
{
{"UserName", "john"}
}
};
````
Felizmente, há uma maneira mais simples de codificar isso:
````C#
throw new BusinessException("App:010046")
.WithData("UserName", "john");
````
Em seguida, o texto localizado pode conter o parâmetro `UserName`:
````json
{
"culture": "pt",
"texts": {
"App:010046": "O nome de usuário deve ser único. '{UserName}' já está em uso!"
}
}
````
* `WithData` pode ser encadeado com mais de um parâmetro (como `.WithData(...).WithData(...)`).
## Mapeamento de Códigos de Status HTTP
O ABP tenta determinar automaticamente o código de status HTTP mais adequado para tipos comuns de exceção seguindo estas regras:
* Para a `AbpAuthorizationException`:
* Retorna `401` (não autorizado) se o usuário não estiver logado.
* Retorna `403` (proibido) se o usuário estiver logado.
* Retorna `400` (requisição inválida) para a `AbpValidationException`.
* Retorna `404` (não encontrado) para a `EntityNotFoundException`.
* Retorna `403` (proibido) para a `IBusinessException` (e `IUserFriendlyException` já que estende a `IBusinessException`).
* Retorna `501` (não implementado) para a `NotImplementedException`.
* Retorna `500` (erro interno do servidor) para outras exceções (que são assumidas como exceções de infraestrutura).
O `IHttpExceptionStatusCodeFinder` é usado para determinar automaticamente o código de status HTTP. A implementação padrão é a classe `DefaultHttpExceptionStatusCodeFinder`. Pode ser substituída ou estendida conforme necessário.
### Mapeamentos Personalizados
A determinação automática do código de status HTTP pode ser substituída por mapeamentos personalizados. Por exemplo:
````C#
services.Configure<AbpExceptionHttpStatusCodeOptions>(options =>
{
options.Map("Volo.Qa:010002", HttpStatusCode.Conflict);
});
````
## Inscrevendo-se nas Exceções
É possível ser informado quando o Framework ABP **manipula uma exceção**. Ele registra automaticamente todas as exceções no [logger padrão](Logging.md), mas você pode querer fazer mais.
Nesse caso, crie uma classe derivada da classe `ExceptionSubscriber` em sua aplicação:
````csharp
public class MeuAssinanteDeExcecao : ExceptionSubscriber
{
public async override Task HandleAsync(ExceptionNotificationContext context)
{
//TODO...
}
}
````
O objeto `context` contém informações necessárias sobre a exceção ocorrida.
> Você pode ter vários assinantes, cada um recebe uma cópia da exceção. As exceções lançadas pelo seu assinante são ignoradas (mas ainda registradas).
## Exceções Integradas
Alguns tipos de exceção são automaticamente lançados pelo framework:
- `AbpAuthorizationException` é lançada se o usuário atual não tiver permissão para realizar a operação solicitada. Consulte [autorização](Authorization.md) para mais informações.
- `AbpValidationException` é lançada se a entrada da solicitação atual não for válida. Consulte [validação](Validation.md) para mais informações.
- `EntityNotFoundException` é lançada se a entidade solicitada não estiver disponível. Isso é lançado principalmente por [repositórios](Repositories.md).
Você também pode lançar esses tipos de exceção em seu código (embora raramente seja necessário).
## AbpExceptionHandlingOptions
`AbpExceptionHandlingOptions` é o principal [objeto de opções](Options.md) para configurar o sistema de tratamento de exceções. Você pode configurá-lo no método `ConfigureServices` do seu [módulo](Module-Development-Basics.md):
````csharp
Configure<AbpExceptionHandlingOptions>(options =>
{
options.SendExceptionsDetailsToClients = true;
options.SendStackTraceToClients = false;
});
````
Aqui está uma lista das opções que você pode configurar:
* `SendExceptionsDetailsToClients` (padrão: `false`): Você pode habilitar ou desabilitar o envio de detalhes da exceção para o cliente.
* `SendStackTraceToClients` (padrão: `true`): Você pode habilitar ou desabilitar o envio da pilha de chamadas da exceção para o cliente. Se você deseja enviar a pilha de chamadas para o cliente, deve definir tanto as opções `SendStackTraceToClients` quanto `SendExceptionsDetailsToClients` como `true`, caso contrário, a pilha de chamadas não será enviada para o cliente.
## Veja Também
* [Tutorial em vídeo](https://abp.io/video-courses/essentials/exception-handling)
Loading…
Cancel
Save