Настройка метода C #, который пытается повторно подключиться к SQL Server через другой порт после первого сбоя

c# sql .net sql-server connection-string

315 просмотра

1 ответ

Я пытаюсь настроить метод, который будет пытаться подключиться к SQL Server сначала через порт по умолчанию (1433), а затем через другой порт, например 7777, в случае сбоя.

Я хочу избежать перестроения строки подключения и попытки подключения снова в случае сбоя, потому что этот метод будет выполняться через заданный интервал времени, и я хочу устранить как можно больше служебных данных.

Я пробовал следующее (любезно предоставлено ConnectionStrings )

public void EstablishConnection()
{
    string ConnectionString = "Data Source=127.0.0.1; Failover Partner=127.0.0.1,7777; Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";

    try
    {
        SqlConnection Connection = new SqlConnection(ConnectionString);
        Connection.Open();
    }
    catch (SqlException)
    {
        // Connection failed 
    }
}

Но исходя из этой статьи и моего тестирования, это не работает так, как я планировал.

Я мог бы легко решить это, выполнив следующее:

public void EstablishConnection()
{
    string ConnectionString = "Data Source=127.0.0.1;Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";

    try
    {
        SqlConnection Connection = new SqlConnection(ConnectionString);
        Connection.Open();
    }
    catch (SqlException)
    {
        try 
        {
          string ConnectionString = "Data Source=127.0.0.1,7777;Initial Catalog=foo;Connection Timeout = 3; Persist Security Info =True;User ID=<id>;Password=<password>";
          SqlConnection Connection = new SqlConnection(ConnectionString);
          Connection.Open();
        } 
        catch (SqlException) 
        {
           // Connection failed 
        }
    }
}

Но это похоже на код спагетти и общую плохую практику.

Также в реальном приложении я не получаю полную строку подключения из файла конфигурации, я извлекаю параметры из файла конфигурации и строю строку конфигурации оттуда.

Автор: Wamadahama Источник Размещён: 06.11.2019 12:22

Ответы (1)


4 плюса

Решение

Прежде всего, давайте определим вспомогательный метод для создания и открытия соединения, пробуя все данные порты:

private SqlConnection TryEstabilishConnection(params int?[] portNumbers) {
    foreach (int? portNumber in portNumbers)
    {
        var connectionString = CreateConnectionStringBuilder();
        if (portNumber != null)
            connectionString.DataSource += $",{portNumber}";

        try {
            var connection = new SqlConnection(connectionString.ToString());
            connection.Open();

            return connection;
        }
        catch (SqlException) {
            // Attempt failed, log?
        }
    }

    // Connection failed with all given ports...
    return null;
}

CreateConnectionStringBuilder()Метод считывает параметры из конфигурации и возвращает готовый к использованию SqlConnectionStringBuilderобъект:

private SqlConnectionStringBuilder CreateConnectionStringBuilder() {
    // ...
}

Ваш код будет:

public void EstabilishConnection() {
    // You can specify more than one alternative port
    var connection = TryEstabilishConnection(null, 7777, 58900);
    if (connection == null) {
        // Oops!
    }
}

Обратите внимание , что если вы не укажете номер порта , он будет пытаться с по умолчанию один (1433) , но также попробовать подключение UDP к 1434 , чтобы задать для динамически назначаемый TCP порта (то Альтернативой порты идея полезна только тогда , когда этот механизм отключен в Конфигурация SQL Server).

Также обратите внимание, что иногда соединение не работает из-за ошибок, связанных с сетью, но экземпляр SQL Server прослушивает порт по умолчанию, вы можете использовать шаблон повторов , я просто обрисую здесь код:

private SqlConnection TryEstabilishConnection(params int?[] portNumbers) {
    foreach (int? portNumber in portNumbers) {
        var connectionString = CreateConnectionStringBuilder();
        if (portNumber != null)
            connectionString.DataSource += $",{portNumber}";

        var connection = TryEstabilishConnection(connectionString.ToString());
        if (connection != null)
            return connection;
    }

    // Connection failed with all given ports...
    return null;
}

private SqlConnection TryEstabilishConnection(string connectionString) {
    for (int i=0; i < RetriesOnError; ++i) {
        try {
            var connection = new SqlConnection(connectionString);
            connection.Open();

            return connection;
        }
        catch (SqlException) when (i < RetriesOnError - 1) {
            Thread.Sleep(DelayBeforeRetry);
        }
    }

    return null;
}

Эти константы являются лишь ориентировочными, для сетевых ошибок могут потребоваться более длительные задержки (или большее количество попыток), но вам, наконец, может потребоваться подождать слишком долго, прежде чем вы получите уведомление о том, что соединение недоступно (и если это происходит часто, вам следует изменить свой UX, чтобы сообщить пользователю о том, что происходит):

private const int RetriesOnError = 5;
private const int DelayBeforeRetry = 1000;

Телефонный код не изменился. Вы можете использовать тот же шаблон и для повторения попыток во время обычных операций, см. Также Узнайте, когда повторять попытку или завершиться неудачей при вызове SQL Server из C #? , В этом случае я предлагаю сохранить соединение, которое работало, чтобы не пытаться снова с портом по умолчанию, если оно не доступно.

Последнее замечание: Failover Partner(должно) работает только для зеркальных баз данных, AFAIK - это не альтернатива, которую Data Source вы можете использовать без какой-либо другой конфигурации SQL Server (но я бы сказал, что это может быть полезной функцией).

Автор: Adriano Repetti Размещён: 07.07.2016 09:23
Вопросы из категории :
32x32