手順 4:ADO.NET で SQL に弾性的に接続するStep 4: Connect resiliently to SQL with ADO.NET

Download-DownArrow-CircledADO.NET をダウンロードするDownload-DownArrow-CircledDownload ADO.NET

このトピックでは、カスタムの再試行ロジックを示す C# コード サンプルを提供します。This topic provides a C# code sample that demonstrates custom retry logic. 再試行ロジックによって信頼性が高まります。The retry logic provides reliability. この再試行ロジックは、プログラムが数秒間待機して再試行すると解消する傾向がある一時的なエラーや一時的な障害を適切に処理することを目的としています。The retry logic is designed to gracefully process temporary errors or transient faults which tend to go away if the program waits several seconds and retries.

一時的な障害の原因には、次のものがあります。Sources of transient faults include:

  • インターネットをサポートするネットワークの短時間の障害。A brief failure of the networking that supports the Internet.
  • クエリが送信された時点で、クラウド システムがリソースの負荷分散を行っている可能性があります。A cloud system might be load balancing its resources at the moment your query was sent.

ローカル Microsoft SQL Server に接続するための ADO.NET クラスでは、Azure SQL Database に接続することもできます。The ADO.NET classes for connecting to your local Microsoft SQL Server can also connect to Azure SQL Database. ただし、ADO.NET クラス自体で、運用環境での使用に必要な堅牢性と信頼性がすべて提供されるわけではありません。However, by themselves the ADO.NET classes cannot provide all the robustness and reliability necessary in production use. クライアント プログラムで一時的な障害が発生しても、そこから通知なしに正常に回復し、処理を続行できる場合があります。Your client program can encounter transient faults from which it should silently and gracefully recover and continue on its own.

手順 1:一時的なエラーを識別するStep 1: Identify transient errors

プログラムでは、一時的なエラーと永続的なエラーを区別する必要があります。Your program must distinguish between transient errors versus persistent errors. 一時的なエラーとは、一時的なネットワークの問題など、短期間で解消する可能性のあるエラー状態です。Transient errors are error conditions that may clear up within a short period of time, such as transient network problems. 永続的なエラーの例として、プログラムにターゲット データベース名のスペルミスが含まれており (この場合は、"そのようなデータベースは見つかりません" というエラーがいつまでも表示されます)、短期間で解消される見込みがない場合が考えられます。An example of a persistent error would be, if your program has a misspelling of the target database name - in this case, the "No such database found" error would persist, and has no chance of clearing up within a short period of time.

一時的な障害として分類されるエラー番号の一覧は、SQL Database クライアント アプリケーションのエラー メッセージに関するページに記載されています。The list of error numbers that are categorized as transient faults is available at Error messages for SQL Database client applications

手順 2:サンプル アプリケーションを作成して実行するStep 2: Create and run sample application

このサンプルは、.NET Framework 4.5.1 以降がインストールされていることを前提としています。This sample assumes .NET Framework 4.5.1 or later is installed. C# のコード サンプルは、Program.cs という名前の 1 つのファイルで構成されます。The C# code sample consists of one file named Program.cs. 次のセクションでコードについて説明します。Its code is provided in the next section.

手順 2.a: サンプル コードをキャプチャしてコンパイルするStep 2.a: Capture and compile the code sample

次の手順で、サンプルをコンパイルができます。You can compile the sample with the following steps:

  1. 無料の Visual Studio Community edition、C# コンソール アプリケーション テンプレートから新しいプロジェクトを作成します。In the free Visual Studio Community edition, create a new project from the C# Console Application template.
    • [ファイル]、[新規作成]、[プロジェクト]、[インストール済み]、[テンプレート]、[Visual C#]、[Windows]、[従来のデスクトップ]、[コンソール アプリケーション] の順にクリックします。File > New > Project > Installed > Templates > Visual C# > Windows > Classic Desktop > Console Application
    • プロジェクトに、「 RetryAdo2」という名前を付けます。Name the project RetryAdo2.
  2. [ソリューション エクスプローラー] ペインを開きます。Open the Solution Explorer pane.
    • プロジェクトの名前を確認します。See the name of your project.
    • Program.cs ファイルの名前を確認します。See the name of the Program.cs file.
  3. Program.cs ファイルを開きます。Open the Program.cs file.
  4. Program.cs ファイルの内容全体を次のコード ブロックのコードに置き換えます。Entirely replace the contents of the Program.cs file with the code in the following code block.
  5. メニューで [ビルド]、[ソリューションのビルド] の順にクリックします。Click the menu Build > Build Solution.

手順 2.b: サンプル コードをコピーして貼り付けるStep 2.b: Copy and paste sample code

このコードを、 Program.cs ファイルに貼り付けます。Paste this code into your Program.cs file.

次にサーバー名、パスワードなどの文字列を編集する必要があります。Then you must edit the strings for server name, password, and so on. これらの文字列は、 GetSqlConnectionStringBuilderという名前のメソッドにあります。You can find these strings in the method named GetSqlConnectionStringBuilder.

注:このサーバー名の接続文字列には tcp: の 4 文字のプレフィックスが含まれているため、Azure SQL Database 向けになっています。NOTE: The connection string for server name is geared toward Azure SQL Database, because it includes the four character prefix of tcp:. ただし、このサーバー文字列は、Microsoft SQL Server に接続するように調整することができます。But you can adjust the server string to connect to your Microsoft SQL Server.

using System;  // C#  
using CG = System.Collections.Generic;  
using QC = Microsoft.Data.SqlClient;  
using TD = System.Threading;  
    
namespace RetryAdo2  
{  
  public class Program  
  {  
    static public int Main(string[] args)  
    {  
      bool succeeded = false;  
      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  
              );  
            TD.Thread.Sleep(1000 * retryIntervalSeconds);  
            retryIntervalSeconds = Convert.ToInt32  
              (retryIntervalSeconds * 1.5);  
          }  
          AccessDatabase();  
          succeeded = true;  
          break;  
        }  
    
        catch (QC.SqlException sqlExc)  
        {  
          if (TransientErrorNumbers.Contains  
            (sqlExc.Number) == true)  
          {  
            Console.WriteLine("{0}: transient occurred.", sqlExc.Number);  
            continue;  
          }  
          else  
          {  
            Console.WriteLine(sqlExc);  
            succeeded = false;  
            break;  
          }  
        }  
    
        catch (TestSqlException sqlExc)  
        {  
          if (TransientErrorNumbers.Contains  
            (sqlExc.Number) == true)  
          {  
            Console.WriteLine("{0}: transient occurred. (TESTING.)", sqlExc.Number);  
            continue;  
          }  
          else  
          {  
            Console.WriteLine(sqlExc);  
            succeeded = false;  
            break;  
          }  
        }  
    
        catch (Exception Exc)  
        {  
          Console.WriteLine(Exc);  
          succeeded = false;  
          break;  
        }  
      }  
    
      if (succeeded == true)  
      {  
        return 0;  
      }  
      else  
      {  
        Console.WriteLine("ERROR: Unable to access the database!");  
        return 1;  
      }  
    }  
    
    /// <summary>  
    /// Connects to the database, reads,  
    /// prints results to the console.  
    /// </summary>  
    static public void AccessDatabase()  
    {  
      //throw new TestSqlException(4060); //(7654321);  // Uncomment for testing.  
    
      using (var sqlConnection = new QC.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>  
    /// You must edit the four 'my' string values.  
    /// </summary>  
    /// <returns>An ADO.NET connection string.</returns>  
    static private string GetSqlConnectionString()  
    {  
      // Prepare the connection string to Azure SQL Database.  
      var sqlConnectionSB = new QC.SqlConnectionStringBuilder();  
    
      // Change these values to your values.  
      sqlConnectionSB.DataSource = "tcp:myazuresqldbserver.database.windows.net,1433"; //["Server"]  
      sqlConnectionSB.InitialCatalog = "MyDatabase"; //["Database"]  
    
      sqlConnectionSB.UserID = "MyLogin";  // "@yourservername"  as suffix sometimes.  
      sqlConnectionSB.Password = "MyPassword";  
      sqlConnectionSB.IntegratedSecurity = false;  
    
      // Adjust these values if you like. (ADO.NET 4.5.1 or later.)  
      sqlConnectionSB.ConnectRetryCount = 3;  
      sqlConnectionSB.ConnectRetryInterval = 10;  // Seconds.  
    
      // Leave these values as they are.  
      sqlConnectionSB.IntegratedSecurity = false;  
      sqlConnectionSB.Encrypt = true;  
      sqlConnectionSB.ConnectTimeout = 30;  
    
      return sqlConnectionSB.ToString();  
    }  
    
    static public CG.List<int> TransientErrorNumbers =  
      new CG.List<int> { 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)  
    { this.Number = testErrorNumber; }  
    
    internal int Number  
    { get; set; }  
  }  
}  

手順 2.c: プログラムの実行Step 2.c: Run the program

RetryAdo2.exe 実行可能ファイルにはパラメーターを入力しません。The RetryAdo2.exe executable inputs no parameters. .exe ファイルを実行するには、次のようにします。To run the .exe:

  1. RetryAdo2.exe バイナリをコンパイルした場所にコンソール ウィンドウを開きます。Open a console window to where you have compiled the RetryAdo2.exe binary.
  2. 入力パラメーターなしで RetryAdo2.exe を実行します。Run RetryAdo2.exe, with no input parameters.
database_firewall_rules_table   245575913  
filestream_tombstone_2073058421 2073058421  
filetable_updates_2105058535    2105058535  

手順 3:再試行ロジックをテストする方法Step 3: Ways to test your retry logic

一時的なエラーをシミュレートして再試行ロジックをテストするには、いくつかの方法があります。There are a variety of ways you can simulate a transient error to test your retry logic.

手順 3.a: テスト例外をスローするStep 3.a: Throw a test exception

コード サンプルには、以下のものが含まれています。The code sample includes:

  • Number という名前のプロパティを含む、TestSqlException という名前の小さな 2 番目のクラス。A small second class named TestSqlException, with a property named Number.
  • //throw new TestSqlException(4060); のコメントを解除できます。//throw new TestSqlException(4060); , which you can uncomment.

throw ステートメントのコメントを解除して再コンパイルすると、RetryAdo2.exe の次回の実行によって次のような行が出力されます。If you uncomment the throw statement, and recompile, the next run of RetryAdo2.exe outputs something similar to the following.

[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\]  
>>  

手順 3.b: 永続的なエラーで再テストするStep 3.b: Retest with a persistent error

コードが永続的なエラーを適切に処理できることを確かめるには、前のテストを再実行します。ただし、4060 などの実際の一時的なエラーの番号は使用しないでください。To prove the code handles persistent errors correctly, rerun the preceding test except do not use the number of a real transient error like 4060. 代わりに、意味のない番号 7654321 を使用します。Instead use the nonsense number 7654321. プログラムはこれを永続的なエラーとして扱い、再試行をすべてバイパスするはずです。The program should treat this as a persistent error, and should bypass any retry.

手順 3.c: ネットワークから切断するStep 3.c: Disconnect from the network

  1. クライアント コンピューターをネットワークから切断します。Disconnect your client computer from the network.
    • デスクトップの場合、ネットワーク ケーブルを外します。For a desktop, unplug the network cable.
    • ラップトップの場合、ファンクション キーの組み合わせを押してネットワーク アダプターをオフにします。For a laptop, press the function combination of keys to turn off the network adapter.
  2. RetryAdo2.exe を起動し、最初の一時的なエラーがコンソールに表示されるのを待ちます (おそらく 11001)。Start RetryAdo2.exe, and wait for the console to display the first transient error, probably 11001.
  3. RetryAdo2.exe が実行している間に、ネットワークに再接続します。Reconnect to the network, while RetryAdo2.exe continues to run.
  4. 続いて行われる再試行が成功したことをコンソールで確認します。Watch the console report success on a subsequent retry.

手順 2.d: 一時的にスペルミスのあるサーバー名を使用するStep 2.d: Temporarily misspell the server name

  1. 一時的に 40615 を別のエラー番号として TransientErrorNumbersに追加し、再コンパイルします。Temporarily add 40615 as another error number to TransientErrorNumbers, and recompile.
  2. new QC.SqlConnectionStringBuilder()の行にブレークポイントを設定します。Set a breakpoint on the line: new QC.SqlConnectionStringBuilder().
  3. [エディット コンティニュ] 機能を使用して、数行下で意図的にサーバー名のスペルを間違えます。Use the Edit and Continue feature to purposely misspell the server name, a couple of lines below.
    • プログラムを実行し、ブレークポイントに戻ります。Let the program run and come back to your breakpoint.
    • 40615 エラーが発生します。The error 40615 occurs.
  4. スペルミスを修正します。Fix the misspelling.
  5. プログラムを実行すると正常に終了します。Let the program run and finish successfully.
  6. 40615 を削除し、再コンパイルします。Remove 40615, and recompile.

次のステップNext steps

他のベスト プラクティスおよびデザイン ガイドラインを調べるには、SQL Database への接続: リンク、ベスト プラクティスおよびデザイン ガイドラインに関するページを参照してください。To explore other best practicies and design guidelines, visit Connecting to SQL Database: Links, Best Practices and Design Guidelines