Tratamento de erros
Nota
O comportamento que este artigo descreve está disponível apenas quando a versão prévia do recurso Gerenciamento de erros no nível da fórmula em Configurações>Próximos recursos>Versão prévia está ativado. Mais Informações: Como controlar quais recursos são habilitados
Erros acontecem. As redes ficam inativas, o armazenamento fica cheio, valores inesperados fluem. É importante que sua lógica continue funcionando adequadamente diante de possíveis problemas.
Por padrão, os erros fluem pelas fórmulas de um aplicativo e são relatados ao usuário final do aplicativo. Dessa forma, o usuário final sabe que algo inesperado aconteceu, pode corrigir o problema sozinho com uma entrada diferente ou pode relatar o problema ao proprietário do aplicativo.
Como criador de app, você pode controlar os erros em seu aplicativo:
- Detecção e tratamento de um erro. Se houver uma chance de ocorrer um erro, as fórmulas do aplicativo poderão ser gravadas para detectar a condição de erro e repetir a operação. O usuário final não precisa se preocupar com a ocorrência de um erro porque o fabricante contou com essa possibilidade. Isso é feito com as funções IfError, IsError e IsErrorOrBlank em uma fórmula.
- Relato de um erro. Se um erro não for tratado na fórmula em que foi encontrado, o erro será adicionado ao manipulador App.OnError. Aqui, o erro não pode mais ser substituído, pois já ocorreu e faz parte dos cálculos da fórmula. Mas você pode usar App.OnError para controlar como o erro é relatado ao usuário final, incluindo a supressão do relatório de erros. App.OnError também fornece um ponto de estrangulamento comum para relatórios de erros em todo o aplicativo.
- Criação e relançamento de um erro. Por fim, você pode detectar uma condição de erro com sua própria lógica, uma condição específica do seu aplicativo. Use a função Error para criar e relatar erros personalizados. A função Error também é usada para relançar um error após ser interrogado em IfError ou App.OnError.
Introdução
Vamos começar com um exemplo simples.
- Crie uma nova tela em um aplicativo de Tela do Power Apps.
- Insira um controle TextInput. O padrão será o nome TextInput1.
- Insira um controle Label.
- Defina a propriedade Text do controle Label para a fórmula .
1/Value( TextInput1.Text )
Ocorreu um erro porque o texto padrão de um controle TextInput é "Text input"
, que não pode ser convertido em um número. Por padrão, isso é bom: o usuário final receberá uma notificação de que algo não está funcionando conforme o esperado no aplicativo.
Obviamente, não desejamos que um erro apareça para o usuário toda vez que ele inicia este aplicativo. É provável que "Text input"
não seja o padrão certo para a caixa de entrada de texto. Para corrigir isso, vamos alterar a propriedade Default do controle TextInput para:
Blank()
Mas, agora temos um erro diferente. Operações matemáticas com a função blank, como divisão, forçarão o valor em branco a ser zerado. Agora isso está causando um erro de divisão por zero. Para corrigir isso, precisamos decidir qual é o comportamento apropriado para esta situação neste aplicativo. A resposta pode ser mostrar blank quando a entrada de texto estiver em branco. Podemos fazer isso agrupando nossa fórmula com a função IfError:
IfError( 1/Value( TextInput1.Text ), Blank() )
Agora o erro foi substituído por um valor válido e a faixa de erros desapareceu. Mas, podemos ter exagerado: o IfError que usamos trata de todos os erros, incluindo a digitação de um valor incorreto como "hello"
. Podemos resolver isso ajustando nosso IfError para lidar apenas com a divisão por zero e relançar todos os outros erros:
IfError( 1/Value( TextInput1.Text ),
If( FirstError.Kind = ErrorKind.Div0, Blank(), Error( FirstError ) ) )
Vamos executar nosso aplicativo e testar alguns valores diferentes.
Sem valor, como quando o aplicativo inicia, não há resposta exibida, pois o valor padrão é em branco, mas nenhum erro exibido como IfError substitui o erro de divisão por zero.
Se digitarmos um 4, obteremos o resultado esperado de 0,25:
Se digitarmos algo ilegal, como hello
, receberemos uma faixa de erros:
Este é um exemplo introdutório simples. O tratamento de erros pode ser feito de várias maneiras distintas, dependendo das necessidades do aplicativo:
- Em vez de uma faixa de erros, poderíamos ter mostrado "#Error" no controle de rótulo com a fórmula. Para manter os tipos das substituições compatíveis com o primeiro argumento para IfError, precisamos converter explicitamente o resultado numérico em uma cadeia de texto com a função Text.
IfError( Text( 1/Value( TextInput1.Text ) ), If( FirstError.Kind = ErrorKind.Div0, Blank(), "#Error" )
- Em vez de agrupar essa instância específica com IfError, poderíamos ter escrito um manipulador App.OnError centralizado. Não podemos substituir a cadeia mostrada por "#Error" porque o erro já ocorreu e App.OnError é fornecido apenas para relatórios de controle.
If( FirstError.Kind <> ErrorKind.Div0, Error( FirstError ) )
Propagação de erros
Os erros fluem pelas fórmulas da mesma forma que no Excel. Por exemplo, no Excel, se a célula A1
tiver a fórmula =1/0
, A1 exibirá o valor do erro #DIV0!
:
Se a célula A2
referir-se a A1
com uma fórmula como =A1*2
, o erro também se propagará por essa fórmula:
O erro substitui o valor que teria sido calculado de outra forma. Não há resultado para a multiplicação na célula A2
, apenas o erro da divisão em A1
.
O Power Fx funciona da mesma forma. Em geral, se um erro for fornecido como um argumento para uma função ou operador, a operação não ocorrerá e o erro de entrada fluirá como resultado da operação. Por exemplo, Mid( Text( 1/0 ), 1, 1 )
retornará um erro de Divisão por Zero, pois o erro mais interno passa pelas funções Text e Mid:
Em geral, os erros não fluem pelas propriedades de controle do Power Apps. Vamos estender o exemplo anterior com um controle adicional que exibe se a propriedade Text
do primeiro rótulo é um estado de erro:
Não há problemas se os erros não se propagarem por um controle porque o sistema observará erros na entrada de todas as propriedades do controle. O erro não será perdido.
A maioria das funções e operadores seguem a regra "entrada de erro, saída de erro", mas há exceções. As funções IsError, IsErrorOrBlank e IfError são criadas para trabalhar com erros; portanto, elas podem não retornar um erro, mesmo que um seja passado para elas.
Observação de erros
Os erros não são observados até que seu valor seja usado.
Como resultado, as funções If e Select também poderão não retornar um erro se um for passado. Considere a fórmula If( false, 1/0, 3 )
. Há um erro de divisão por zero presente nesta fórmula, mas como o If
não ocupa essa ramificação por causa do false
, o Power Fx e o Power Apps não relatarão um erro:
Usar a função Set com um erro não relatará um erro no ponto em que o erro é colocado na variável. Por exemplo, no Power Apps, existe uma fórmula em App.OnStart que insere um erro de divisão por zero na variável x
:
Nenhum erro é relatado porque x
não é referenciado. No entanto, no momento em que adicionamos um controle de rótulo e definimos a propriedade Text como x
, o erro é exibido:
Você pode observar erros em uma fórmula com as funções IfError, IsError e IsErrorOrBlank. Com essas funções, você pode retornar um valor alternativo, executar uma ação alternativa ou modificar o erro antes que ele seja observado e relatado.
Relato de erros
Ao encontrar um erro, a próxima etapa é relatá-lo ao usuário final.
Diferente do Excel, nem sempre há um local conveniente para mostrar um resultado de erro, pois o resultado de uma fórmula pode direcionar uma propriedade como as coordenadas X e Y de um controle para o qual não há local conveniente para mostrar um texto. Cada host do Power Fx controla como os erros são exibidos ao usuário final e qual é o controle do criador sobre esse processo. No Power Apps, uma faixa de erros é mostrada e o App.OnError é usado para controlar como o erro é relatado.
É importante notar que o App.OnError não pode substituir o erro da mesma forma que o IfError. No ponto em que App.OnError é executado, o erro já ocorreu e o resultado foi propagado por meio de outras fórmulas. App.OnError controla apenas como o erro é relatado ao usuário final e fornece um gancho para o criador registrar o erro, se desejado.
As variáveis de escopo FirstError e AllErrors fornecem informações de contexto sobre o(s) erro(s). Isso fornece informações sobre o tipo de erro, sua origem e onde foi observado.
Interrupção após um erro
As fórmulas de comportamento dão suporte à ação, modificando bancos de dados e alterando o estado. Essas fórmulas permitem que mais de uma ação seja executada em uma sequência usando o ;
operador de encadeamento (ou ;;
dependendo da localidade).
Neste caso, por exemplo, o controle de grade mostra o que está na tabela T
. Cada seleção de botão altera o estado nesta tabela com duas chamadas Patch:
Em uma fórmula de comportamento encadeado, as ações não param após o primeiro erro. Vamos modificar nosso exemplo para passar um número de índice inválido na primeira chamada Patch . O segundo Patch continua, apesar do erro anterior. O primeiro erro é relatado ao usuário final, e mostrado como um erro no Studio no controle:
IfError pode ser usado para interromper a execução após um erro. Semelhante à função If, o terceiro argumento dessa função fornece um local para inserir ações que deverão ser executadas apenas se não houver erro:
Se um erro for encontrado durante uma das iterações de ForAll, as demais iterações não serão interrompidas. ForAll foi projetado para executar cada iteração de forma independente, permitindo a execução paralela. Quando o ForAll estiver concluído, um erro será retornado, contendo todos os erros encontrados (examinando AllErrors em IfError ou App.OnError).
Por exemplo, a fórmula a seguir resultará em ForAll retornando dois erros (para a divisão por zero para Value
de 0, duas vezes) e Collection
terá três registros (para quando Value
não for 0): [1, 2, 3]
.
Clear( Collection );
ForAll( [1,0,2,0,3], If( 1/Value > 0, Collect( Collection, Value ) ) );
Trabalhar com vários erros
Como uma fórmula de comportamento pode executar mais de uma ação, ela também pode encontrar mais de um erro.
Por padrão, o primeiro erro é relatado ao usuário final. Neste exemplo, ambas as chamadas Patch falharão, a segunda com um erro de divisão por zero. Apenas o primeiro erro (sobre o índice) é mostrado ao usuário:
A função IfError e App.OnError podem acessar todos os erros encontrados com a variável de escopo AllErrors . Nesse caso, podemos definir isso como uma variável global e examinar os dois erros encontrados. Eles aparecem na tabela na mesma ordem em que foram encontrados:
Vários erros também podem ser retornados em fórmulas sem comportamento. Por exemplo, usar a função Patch com um lote de registros para atualizar pode retornar vários erros, um para cada registro com falha.
Erros em tabelas
Como vimos anteriormente, os erros podem ser armazenados em variáveis. Erros também podem ser incluídos em estruturas de dados, como tabelas. Isso é importante para que um erro em um registro não invalide a tabela inteira.
Por exemplo, considere este controle de tabela de dados no Power Apps:
O cálculo em AddColumns encontrou um erro de divisão por zero para um dos valores. Para esse registro, a coluna Reciprocal tem um valor de erro (divisão por zero), mas os outros registros não e não há problema. IsError( Index( output, 2 ) )
retorna falso e IsError( Index( output, 2 ).Value )
retorna verdadeiro.
Se ocorrer um erro ao filtrar uma tabela, o registro inteiro será um erro, mas ainda será retornado no resultado para que o usuário final saiba que há um problema.
Imagine este exemplo. Aqui, a tabela original não tem erros, mas o ato de filtrar gera um erro sempre que Value é igual a 0:
Os valores -5 e -3 são devidamente filtrados. Os valores 0 resultam em um erro no processamento do filtro e, portanto, não fica claro se o registro deve ser incluído ou não no resultado. Para maximizar a transparência para os usuários finais e ajudar os criadores a depurar, incluímos um registro de erro em vez do original. Nesse caso, IsError( Index( output, 2 ) )
retorna true.
Erros na fonte de dados
As funções que modificam dados em fontes de dados, como Patch, Collect, Remove, RemoveIf, Update, UpdateIf e SubmitForm relatam erros de duas maneiras:
- Cada uma dessas funções retornará um valor de erro como resultado da operação. Erros podem ser detectados com IsError e substituídos ou suprimidos com IfError e App.OnError como de costume.
- Após a operação, a função Errors também retornará os erros das operações anteriores. Isso pode ser útil para exibir a mensagem de erro em uma tela de formulário sem precisar capturar o erro em uma variável de estado.
Por exemplo, esta fórmula verificará um erro de Collect e exibirá uma mensagem de erro personalizada:
IfError( Collect( Names, { Name: "duplicate" } ),
Notify( $"OOPS: { FirstError.Message }", NotificationType.Warning ) )
A função Errors também retorna informações sobre erros anteriores durante operações de tempo de execução. Isso pode ser útil para exibir um erro em uma tela de formulário, sem precisar capturar o erro em uma variável de estado.
Relançar erros
Às vezes, alguns erros potenciais são esperados e podem ser ignorados com segurança. No IfError e no App.OnError, se for detectado um erro que deva ser passado para o próximo manipulador superior, ele poderá ser relançado com Error( AllErrors )
.
Criar seus próprios erros
Você também pode criar seus próprios erros com a função Error.
Se estiver criando seus próprios erros, será recomendável usar valores acima de 1.000 para evitar possíveis conflitos com futuros valores de erro do sistema.
Valores de enumeração ErrorKind
Enumeração ErrorKind | Valor | Description |
---|---|---|
AnalysisError | 18 | Erro do sistema. Ocorreu um problema com a análise do compilador. |
BadLanguageCode | 14 | Um código de idioma inválido ou não reconhecido foi usado. |
BadRegex | 15 | Expressão regular inválida. Verifique a sintaxe usada com as funções IsMatch, Match ou MatchAll. |
Conflito | 6 | O registro atualizado já foi alterado na fonte e o conflito precisa ser resolvido. Uma solução comum é salvar as alterações locais, atualizar o registro e reaplicar as alterações. |
ConstraintViolated | 8 | O registro não passou em uma verificação de restrição no servidor. |
CreatePermission | 3 | O usuário não tem permissão para criar registros para a fonte de dados. Por exemplo, a função Collect foi chamada. |
DeletePermissions | 5 | O usuário não tem permissão para excluir registros para a fonte de dados. Por exemplo, a função Remove foi chamada. |
Div0 | 13 | Divisão por zero. |
EditPermissions | 4 | O usuário não tem permissão para criar registros para a fonte de dados. Por exemplo, a função Patch foi chamada. |
GeneratedValue | 9 | Um valor foi passado de forma errada ao servidor para um campo que é calculado automaticamente pelo servidor. |
InvalidFunctionUsage | 16 | Uso inválido de uma função. Em geral, um ou mais argumentos da função estão incorretos ou são usados de forma inválida. |
FileNotFound | 17 | Não foi possível localizar o armazenamento SaveData. |
InsufficientMemory | 21 | Não há memória ou armazenamento suficiente no dispositivo para a operação. |
InvalidArgument | 25 | Um argumento inválido foi passado para uma função. |
Internos | 26 | Erro do sistema. Houve um problema interno com uma das funções. |
MissingRequired | 2 | Um campo obrigatório de um registro estava ausente. |
Rede | 23 | Houve um problema com as comunicações da rede. |
Nenhum | 0 | Erro do sistema. Não há erro. |
Não Aplicável | 27 | Não há valor disponível. Útil para diferenciar um valor em branco que pode ser tratado como zero em cálculos numéricos de valores em branco que deverão ser sinalizados como um problema potencial se o valor for usado. |
NotFound | 7 | Não foi possível encontrar o registro. Por exemplo, o registro a ser modificado na função Patch. |
NotSupported | 20 | Operação sem suporte para este player ou dispositivo. |
Numérico | 24 | Uma função numérica foi usada de forma imprópria. Por exemplo, substitua Sqrt por -1. |
QuoteExceeded | 22 | Cota de armazenamento excedida. |
ReadOnlyValue | 10 | Essa coluna é somente leitura e não pode ser modificada. |
ReadPermission | 19 | O usuário não tem permissão para ler registros para a fonte de dados. |
Sincronizar | 0 | Um erro foi relatado pela fonte de dados. Verifique a coluna Mensagem para obter mais informações. |
Desconhecido | 12 | Ocorreu um erro, mas de um tipo desconhecido. |
Validação | 11 | O registro não passou em uma verificação de validação. |