Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
- Article précédent : Étape 3 : Preuve de concept pour la connexion à SQL en utilisant ADO.NET
Cet article fournit un exemple de code C# qui démontre la logique de réessayage implémentée manuellement. La logique de réessai gère les erreurs temporaires, ou défauts transitoires, qui pourraient disparaître si le programme attend et tente à nouveau l’opération.
Important
Pour les nouvelles applications qui utilisent Microsoft. Data.SqlClient 3.0 et versions ultérieures préfèrent la logique de réessayage configurable du pilote plutôt que d'implémenter une boucle de réessayage. Commencez par configurer la logique de réessai dans SqlClient.
Les sources des défaillances transitoires incluent :
- Une brève défaillance du réseau qui supporte Internet.
- Un système cloud peut équilibrer la charge de ses ressources lorsque votre requête arrive.
Les classes ADO.NET pour se connecter à SQL Server peuvent également se connecter à Azure SQL Database. Votre programme client peut rencontrer des pannes transitoires. Il doit récupérer en utilisant une politique de réessai bornée adaptée à l’opération.
Étape 1 : Identification des erreurs temporaires
Votre programme doit distinguer les erreurs transitoires des erreurs persistantes. Les erreurs transitoires sont des conditions d’erreur qui peuvent disparaître rapidement, comme les problèmes de réseau transitoire. Un exemple d’erreur persistante est une faute d’orthographe du nom de la base de données cible. Dans ce cas, l’erreur « Aucune base de données de ce type trouvée » persiste et ne disparaît pas rapidement.
La liste des numéros d’erreur classés comme défauts transitoires est disponible à l’article Messages d’erreur pour les applications clients de base de données SQL.
Étape 2 : Créer et exécuter un exemple d’application
L’exemple part du principe que .NET Framework 4.6.2 ou une version ultérieure est installé. L’exemple de code C# se compose d’un fichier nommé Program.cs. Le code correspondant est fourni dans la section suivante.
Étape 2.a : Capturer et compiler l’exemple de code
Vous pouvez compiler l'exemple en effectuant les étapes suivantes :
Dans l’ édition Visual Studio Community gratuite, créez un projet à partir du modèle Application console C#.
Sélectionnez Fichier>Nouveau>Projet>Installés>Modèles>Visual C#>Windows>Bureau classique>Application console.
Nommez le projet
RetryAdo2.
Ouvrez le volet Explorateur de solutions.
- Consultez le nom de votre projet.
- Sur votre projet, ajoutez une dépendance NuGet au package Microsoft.Data.SqlClient.
- Voir le nom du
Program.csfichier.
Ouvrez le fichier
Program.cs.Remplacez l’intégralité du contenu du
Program.csfichier par le code du bloc de code suivant.Sélectionnez le menu Build>Build Solution.
Étape 2.b : Copiez et collez l’exemple de code
Collez ce code dans votre Program.cs fichier.
Ensuite, modifier les chaînes pour le nom du serveur et le mot de passe. Vous pouvez trouver ces chaînes dans la méthode nommée GetSqlConnectionString.
Note
La chaîne de connexion est orientée vers Azure SQL Database, car elle inclut le préfixe tcp:de quatre caractères . Mais vous pouvez ajuster la chaîne serveur pour qu’elle se connecte à votre instance 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; }
}
Étape 2.c : Exécuter le programme
L’exécutable RetryAdo2.exe ne prend pas de paramètres. Pour exécuter le .exe :
- Ouvre une fenêtre de console dans le dossier où tu as compilé le
RetryAdo2.exebinaire. - Exécute
RetryAdo2.exesans paramètres d’entrée.
database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535
Étape 3 : Méthodes pour tester votre logique de nouvelle tentative
Vous pouvez simuler une erreur transitoire pour tester votre logique de réessai de plusieurs manières.
Étape 3.a : Lever une exception de test
L’exemple de code inclut ce qui suit :
- Une petite seconde classe nommée
TestSqlExceptionavec une propriété nomméeNumber. -
//throw new TestSqlException(4060);, dont vous pouvez supprimer les marques de commentaire.
Si vous retirez le commentaire de l’instruction throw et que vous recompilez, la série RetryAdo2.exe suivante donne quelque chose de similaire à ce qui suit.
[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\]
>>
Étape 3.b : Tester à nouveau avec une erreur persistante
Pour prouver que le code gère correctement les erreurs persistantes, relancez le test précédent. Au lieu d’utiliser un vrai numéro d’erreur transitoire comme 4060, utilisez le nombre fictif 7654321. Le programme considère ce chiffre comme une erreur persistante et contourne toute nouvelle tentative.
Étape 3.c : Se déconnecter du réseau
- Déconnectez votre ordinateur client du réseau.
- Pour un ordinateur de bureau, débranchez le câble réseau.
- Pour un ordinateur portable, appuyez sur la combinaison de touches permettant de désactiver la carte réseau.
- Lancez,
RetryAdo2.exeet attendez que la console affiche la première erreur transitoire, probablement 11001. - Reconnectez-vous au réseau, pendant que
RetryAdo2.execontinue de fonctionner. - Observez que la console signale une réussite lors d’une nouvelle tentative.
Étape 3.d : saisir temporairement incorrectement le nom du serveur
- Ajouter temporairement 40615 comme un autre numéro d’erreur à
TransientErrorNumbers, et recompiler. - Définissez un point d’arrêt sur la ligne :
new QC.SqlConnectionStringBuilder(). - Utilisez la fonctionnalité Modifier et continuer pour orthographier exprès de manière incorrecte le nom du serveur, quelques lignes plus bas.
- Laissez le programme s’exécuter et revenez à votre point d’arrêt.
- L’erreur 40615 se produit.
- Corrigez la faute d’orthographe.
- Laissez le programme s’exécuter et se terminer correctement.
- Supprimez 40615 et recompilez.