Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
- Vorheriger Artikel: Schritt 3: Konzeptnachweis für die Verbindung zu SQL mit ADO.NET
Dieser Artikel bietet ein Beispiel für einen C#-Code, das manuell implementierte Wiederholungslogik demonstriert. Die Retry-Logik behandelt temporäre Fehler oder vorübergehende Fehler, die sich beheben können, wenn das Programm wartet und die Operation erneut versucht.
Von Bedeutung
Für neue Anwendungen, die Microsoft.Data.SqlClient 3.0 oder höher verwenden, sollte die konfigurierbare Wiederholungslogik des Treibers bevorzugt werden, anstatt selbst eine Wiederholungsschleife zu implementieren. Beginnen Sie mit Configure Retry Logic in SqlClient.
Quellen vorübergehender Fehler sind u. a.:
- Ein kurzer Ausfall des Netzwerks, das das Internet unterstützt.
- Ein Cloud-System könnte seine Ressourcen ausbalancieren, wenn Ihre Anfrage eintrifft.
Die ADONET-Klassen zur Verbindung mit SQL Server können sich ebenfalls mit der Azure SQL-Datenbank verbinden. Dein Client-Programm kann vorübergehende Fehler haben. Es sollte sich mithilfe einer begrenzten Wiederholungsstrategie wiederherstellen lassen, die für den Vorgang geeignet ist.
Schritt 1: Ermitteln vorübergehender Fehler
Ihr Programm muss zwischen vorübergehenden und persistenten Fehlern unterscheiden. Vorübergehende Fehler sind Fehlerzustände, die sich in kurzer Zeit beheben können, wie zum Beispiel vorübergehende Netzwerkprobleme. Ein Beispiel für einen persistenten Fehler ist eine falsche Rechtschreibung des Zieldatenbank-Namens. In diesem Fall bleibt der Fehler "Keine solche Datenbank gefunden" bestehen und verschwindet nicht schnell.
Die Liste der Fehlernummern, die als vorübergehende Fehler kategorisiert sind, ist unter Fehlermeldungen für SQL-Datenbank-Clientanwendungen verfügbar.
Schritt 2: Erstellen und Ausführen einer Beispielanwendung
Bei dem Beispiel wird davon ausgegangen, dass .NET Framework 4.6.2 oder höher installiert ist. Das C#-Codebeispiel besteht aus einer Datei namens Program.cs. Den Code dazu finden Sie im nächsten Abschnitt.
Schritt 2.a: Erfassen und Kompilieren des Codebeispiels
Sie können das Beispiel mit den folgenden Schritten kompilieren:
Erstellen Sie in der kostenlosen Visual Studio Community Editionein neues Projekt mit der Vorlage für die C#-Konsolenanwendung.
Wählen Sie Datei>Neu>Projekt>Installiert>Vorlagen>Visual C#>Windows>Klassischer Desktop>Konsolenanwendung aus.
Benennen Sie das Projekt
RetryAdo2.
Öffnen Sie den Bereich „Projektmappen-Explorer“.
- Beachten Sie den Namen des Projekts.
- Fügen Sie eine NuGet Abhängigkeit vom Microsoft.Data.SqlClient-Paket in Ihrem Projekt hinzu.
- Sehen Sie sich den Namen der
Program.csDatei an.
Öffnen Sie die Datei
Program.cs.Ersetzen Sie den gesamten Inhalt der
Program.csDatei durch den Code im folgenden Codeblock.Wählen Sie das Menü Build>Build Solution aus.
Schritt 2.b: Kopieren und Einfügen des Beispielcodes
Fügen Sie diesen Code in Ihre Program.cs Datei ein.
Dann bearbeite ich die Zeichenketten für Servernamen und Passwort. Diese Strings findest du in der Methode namens GetSqlConnectionString.
Anmerkung
Die Verbindungszeichenfolge ist auf Azure SQL-Datenbank ausgerichtet, da sie das vierstellige Präfix tcp:enthält. Aber du kannst den Serverstring so anpassen, dass er sich mit deiner SQL Server-Instanz verbindet.
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; }
}
Schritt 2.c: Ausführen des Programms
Die RetryAdo2.exe ausführbare Datei akzeptiert keine Parameter. Um .exe auszuführen:
- Öffne ein Konsolenfenster in dem Ordner, in dem du die
RetryAdo2.exeBinärdatei kompiliert hast. - Führe
RetryAdo2.exeohne Eingabeparameter aus.
database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535
Schritt 3: Möglichkeiten um Ihre Wiederholungslogik zu testen
Man kann einen vorübergehenden Fehler simulieren, um die Logik des Wiederholens auf verschiedene Arten zu testen.
Schritt 3.a: Auslösen einer Testausnahme
Das Codebeispiel beinhaltet:
- Eine kleine zweite Klasse namens
TestSqlExceptionmit einer Eigenschaft namensNumber. -
//throw new TestSqlException(4060);, wofür Sie die Auskommentierung aufheben können.
Wenn du die Throw-Anweisung entkommentierst und neu kompilierst, liefert der nächste Durchlauf RetryAdo2.exe etwas Ähnliches wie das folgende aus.
[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\]
>>
Schritt 3.b: Erneutes Testen mit einem beständigen Fehler
Um zu beweisen, dass der Code persistente Fehler korrekt handhabt, führen Sie den vorherigen Test erneut durch. Anstatt eine reale transientistische Fehlerzahl wie 4060 zu verwenden, verwenden Sie die fiktive Zahl 7654321. Das Programm behandelt diese Zahl als persistierenden Fehler und umgeht jeden erneuten Versuch.
Schritt 3.c: Trennen vom Netzwerk
- Trennen Sie den Clientcomputer vom Netzwerk.
- Bei einem Desktop-Computer stecken Sie das Netzwerkkabel aus.
- Bei einem Laptop drücken Sie die Tastenkombination um den Netzwerkadapter auszuschalten.
- Starte
RetryAdo2.exe, und warte, bis die Konsole den ersten transienten Fehler anzeigt, wahrscheinlich 11001. - Stellen Sie die Verbindung mit dem Netzwerk wieder her, während
RetryAdo2.exeweiter ausgeführt wird. - Beobachten Sie bei einem späteren erneuten Versuch, wie die Konsole den Erfolg meldet.
Schritt 3.d: Temporäres Falschschreiben des Servernamens
- Füge vorübergehend 40615 als weitere Fehlernummer hinzu
TransientErrorNumbersund kompiliere erneut. - Setzen Sie einen Haltepunkt in der Zeile:
new QC.SqlConnectionStringBuilder(). - Verwenden Sie die Funktion Bearbeiten und fortfahren, um einige Zeilen tiefer den Servernamen absichtlich falsch zu schreiben.
- Lassen Sie das Programm laufen und kehren Sie zu Ihrem Haltepunkt zurück.
- Der Fehler „40615“ tritt auf.
- Beheben Sie den Rechtschreibfehler.
- Lassen Sie das Programm laufen und erfolgreich abschließen.
- Entfernen Sie „40615“ und kompilieren Sie erneut.