Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
- Artigo anterior: Etapa 3: Prova de conceito conectando-se ao SQL usando ADO.NET
Este artigo apresenta um exemplo de código C# que demonstra a lógica de repetição implementada de forma manual. A lógica de repetição lida com erros temporários, ou falhas transitórias, que podem ser corrigidos se o programa esperar e tentar novamente a operação.
Importante
Para novas aplicações que utilizem o Microsoft.Data.SqlClient 3.0 e versões posteriores, dê preferência à lógica de repetição configurável do controlador, em vez de implementar um ciclo de repetição. Comece por Configurar a lógica de repetição no SqlClient.
As fontes de falhas transitórias incluem:
- Uma breve falha da rede que suporta a Internet.
- Um sistema cloud pode estar a equilibrar os seus recursos quando a sua consulta chega.
As classes ADO.NET para ligação ao SQL Server também podem ligar-se ao Base de Dados SQL do Azure. O seu programa cliente pode encontrar falhas transitórias. Deve recuperar-se utilizando uma política de retentativas limitada que seja adequada para a operação.
Etapa 1: Identificar erros transitórios
O seu programa deve distinguir entre erros transitórios e erros persistentes. Erros transitórios são condições de erro que podem desaparecer rapidamente, como problemas de rede transitória. Um exemplo de erro persistente é um erro ortográfico do nome da base de dados de destino. Nesse caso, o erro "Nenhuma base de dados encontrada" persiste e não desaparece rapidamente.
A lista de números de erro categorizados como falhas transitórias está disponível em Mensagens de erro para aplicações cliente de base de dados SQL.
Etapa 2: Criar e executar o aplicativo de exemplo
Este exemplo pressupõe que o .NET Framework 4.6.2 ou posterior esteja instalado. O exemplo de código C# consiste num ficheiro chamado Program.cs. Seu código é fornecido na próxima seção.
Etapa 2.a: Capturar e compilar o exemplo de código
Você pode compilar o exemplo com as seguintes etapas:
No edição gratuita do Visual Studio Community, crie um novo projeto a partir do modelo Aplicativo de Console do C#.
Selecione Ficheiro>NovoProjeto>>>Modelos>Visual C#>Windows>Ambiente de Trabalho Clássico>Aplicação de Consola.
Nomeie o projeto
RetryAdo2.
Abra o painel Gerenciador de Soluções.
- Veja o nome do seu projeto.
- No seu projeto , adicione uma dependência NuGet ao pacote Microsoft.Data.SqlClient.
- Veja o nome do
Program.csficheiro.
Abra o ficheiro
Program.cs.Substitua todo o conteúdo do
Program.csficheiro pelo código do bloco de código seguinte.Selecione o menu Build>Build Solution.
Etapa 2.b: Copiar e colar o código de exemplo
Cola este código no teu Program.cs ficheiro.
Depois, edita as strings para o nome do servidor e a palavra-passe. Pode encontrar estas cadeias no método chamado GetSqlConnectionString.
Observação
A cadeia de ligação é orientada para o Base de Dados SQL do Azure, porque inclui o prefixo tcp:de quatro caracteres . Mas pode ajustar a cadeia de caracteres do servidor para estabelecer ligação à sua instância do SQL Server.
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Threading;
namespace RetryAdo2;
public class Program
{
public static int Main(string[] args)
{
bool succeeded = false;
const int totalNumberOfTimesToTry = 4;
int retryIntervalSeconds = 10;
for (int tries = 1; tries <= totalNumberOfTimesToTry; tries++)
{
try
{
if (tries > 1)
{
Console.WriteLine(
"Transient error encountered. Will begin attempt number {0} of {1} max...",
tries,
totalNumberOfTimesToTry
);
Thread.Sleep(1000 * retryIntervalSeconds);
retryIntervalSeconds = Convert.ToInt32(retryIntervalSeconds * 1.5);
}
AccessDatabase();
succeeded = true;
break;
}
catch (SqlException sqlExc) {
if (TransientErrorNumbers.Contains(sqlExc.Number))
{
Console.WriteLine("{0}: transient occurred.", sqlExc.Number);
continue;
}
Console.WriteLine(sqlExc);
break;
}
catch (TestSqlException sqlExc) {
if (TransientErrorNumbers.Contains(sqlExc.Number))
{
Console.WriteLine("{0}: transient occurred. (TESTING.)", sqlExc.Number);
continue;
}
Console.WriteLine(sqlExc);
break;
}
catch (Exception e)
{
Console.WriteLine(e);
break;
}
}
if (!succeeded) {
Console.WriteLine("ERROR: Unable to access the database!");
return 1;
}
return 0;
}
/// <summary>
/// Connects to the database, reads,
/// prints results to the console.
/// </summary>
static void AccessDatabase() {
//throw new TestSqlException(4060); //(7654321); // Uncomment for testing.
using var sqlConnection = new SqlConnection(GetSqlConnectionString());
using var dbCommand = sqlConnection.CreateCommand();
dbCommand.CommandText = @"
SELECT TOP 3
ob.name,
CAST(ob.object_id as NVARCHAR(32)) AS [object_id]
FROM sys.objects AS ob
WHERE ob.type='IT'
ORDER BY ob.name;";
sqlConnection.Open();
var dataReader = dbCommand.ExecuteReader();
while (dataReader.Read())
{
Console.WriteLine(
"{0}\t{1}",
dataReader.GetString(0),
dataReader.GetString(1)
);
}
}
/// <summary>
/// Edit the four string values in accordance with your environment.
/// </summary>
/// <returns>An ADO.NET connection string.</returns>
static private string GetSqlConnectionString()
{
// Prepare the connection string to Azure SQL Database.
var sqlConnectionSB = new SqlConnectionStringBuilder
{
// Change these values to your values.
DataSource = "tcp:myazuresqldbserver.database.windows.net,1433", //["Server"]
InitialCatalog = "MyDatabase", //["Database"]
UserID = "MyLogin", // "@yourservername" as suffix sometimes.
Password = "<password>",
// Adjust these values if you like. (ADO.NET 4.5.1 or later.)
ConnectRetryCount = 3,
ConnectRetryInterval = 10, // Seconds.
// Leave these values as they are.
IntegratedSecurity = false,
Encrypt = true,
ConnectTimeout = 30
};
return sqlConnectionSB.ToString();
}
static List<int> TransientErrorNumbers = new()
{
4060, 40197, 40501, 40613, 49918, 49919, 49920, 11001
};
}
/// <summary>
/// For testing retry logic, you can have method
/// AccessDatabase start by throwing a new
/// TestSqlException with a Number that does
/// or does not match a transient error number
/// present in TransientErrorNumbers.
/// </summary>
internal class TestSqlException : ApplicationException
{
internal TestSqlException(int testErrorNumber)
{
Number = testErrorNumber;
}
internal int Number { get; set; }
}
Passo 2.c: Executar o programa
O RetryAdo2.exe executável não aceita parâmetros. Para executar o .exe:
- Abre uma janela de consola na pasta onde compilaste o
RetryAdo2.exebinário. - Executa
RetryAdo2.exesem parâmetros de entrada.
database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535
Etapa 3: Maneiras de testar a sua lógica de reintento
Pode simular um erro transitório para testar a lógica de nova tentativa de várias formas.
Etapa 3.a: Lançar uma exceção de teste
O exemplo de código inclui:
- Uma pequena segunda classe nomeada
TestSqlExceptioncom uma propriedade chamadaNumber. -
//throw new TestSqlException(4060);, que você pode descomentar.
Se descomentares a instrução `throw` e recompilares, a execução seguinte de RetryAdo2.exe produz algo semelhante ao seguinte.
[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>> RetryAdo2.exe
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 2 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 3 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 4 of 4 max...
4060: transient occurred. (TESTING.)
ERROR: Unable to access the database!
[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>>
Etapa 3.b: Teste novamente com um erro persistente
Para provar que o código lida corretamente com erros persistentes, reexecute o teste anterior. Em vez de usar um número de erro transitório real como o 4060, use o número fictício 7654321. O programa trata este número como um erro persistente e ignora qualquer retentativa.
Etapa 3.c: Desconectar da rede
- Desconecte o computador cliente da rede.
- Para um ambiente de trabalho, desligue o cabo de rede.
- Para um laptop, pressione a combinação de teclas de função para desligar o adaptador de rede.
- Inicia
RetryAdo2.exe, e espera que a consola mostre o primeiro erro transitório, provavelmente 11001. - Reconecte-se à rede, enquanto
RetryAdo2.execontinua a funcionar. - Veja o console relatar o sucesso em uma nova tentativa subsequente.
Etapa 3.d: Escrever temporariamente incorretamente o nome do servidor
- Adicionar temporariamente 40615 como outro número de erro a
TransientErrorNumbers, e recompilar. - Defina um ponto de interrupção na linha:
new QC.SqlConnectionStringBuilder(). - Use o recurso Editar e Continuar para escrever propositalmente incorretamente o nome do servidor, algumas linhas abaixo.
- Deixe o programa ser executado e volte ao seu ponto de interrupção.
- O erro 40615 ocorre.
- Corrija o erro ortográfico.
- Deixe o programa ser executado e concluído com êxito.
- Remova 40615 e recompile.