Каков наилучший способ проверить соединение с SQL Server программно?

Мне нужно разработать одну подпрограмму, которая будет запускаться каждые 5 минут, чтобы проверить, работает ли список SQL Server (от 10 до 12).

Я могу попытаться получить простой запрос на каждом из серверов, но это означает, что мне нужно создать таблицу, представление или хранимую процедуру на каждом сервере, даже если я использую какой-либо уже созданный SP, мне нужно иметь зарегистрированного пользователя на каждом сервере. сервер тоже. Серверы не находятся в одном и том же физическом месте, поэтому выполнение этих требований будет сложной задачей. Есть ли способ просто "пинговать" из C# один SQL Server?

Заранее спасибо!

13 ответов

Решение

Казнить SELECT 1 и проверьте, возвращает ли ExecuteScalar 1.

У меня были проблемы с EF, когда соединение с сервером остановлено или приостановлено, и я поднял тот же вопрос. Так что для полноты приведенных ответов здесь приведен код.

/// <summary>
/// Test that the server is connected
/// </summary>
/// <param name="connectionString">The connection string</param>
/// <returns>true if the connection is opened</returns>
private static bool IsServerConnected(string connectionString)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        try
        {
            connection.Open();
            return true;
        }
        catch (SqlException)
        {
            return false;
        }
    }
}

Смотрите следующий проект на GitHub: https://github.com/ghuntley/csharp-mssql-connectivity-tester

try
{
    Console.WriteLine("Connecting to: {0}", AppConfig.ConnectionString);
    using (var connection = new SqlConnection(AppConfig.ConnectionString))
    {
        var query = "select 1";
        Console.WriteLine("Executing: {0}", query);

        var command = new SqlCommand(query, connection);

        connection.Open();
        Console.WriteLine("SQL Connection successful.");

        command.ExecuteScalar();
        Console.WriteLine("SQL Query execution successful.");
    }
}
catch (Exception ex)
{
    Console.WriteLine("Failure: {0}", ex.Message);
}

Разве установление соединения с базой данных не сделает это для вас? Если база данных не работает, вы не сможете установить соединение.

Найдите открытый приемник на порту 1433 (порт по умолчанию). Если после создания tcp-соединения вы получите какой-либо ответ, возможно, сервер работает.

Для того, что предложил Joel Coehorn, вы уже пробовали утилиту с именем tcping. Я знаю, что это то, что вы не делаете программно. Это автономный исполняемый файл, который позволяет пинговать каждый указанный интервал времени. Это не в C#, хотя. Кроме того, я не уверен, что это сработает, если на целевой машине установлен брандмауэр.

[Я новичок на этом сайте и по ошибке добавил это как комментарий, теперь добавил это как ответ. Дайте мне знать, если это можно сделать здесь, поскольку у меня есть дубликаты комментариев (как комментарий и как ответ) здесь. Я не могу удалить комментарии здесь.]

Спасибо user835921

/questions/1573809/kakov-nailuchshij-sposob-proverit-soedinenie-s-sql-server-programmno/1573819#1573819

Я добавил сюда код:

      /// <summary>
        /// Test that the server is connected
        /// </summary>
        /// <param name="connectionString">The connection string</param>
        /// <returns>true if the connection is opened</returns>
        public static (bool isConnected, string sqlErrorMessage) IsServerConnected(string connectionString)
        {
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                try
                {
                    connection.Open();
                    return (true, "");
                }
                catch (SqlException ex)
                {
                    return (false, ex.Message);
                }
            }
        }

Тогда позвони

      string connectionString = $@"Server={txtServerName.Text.Trim()};Database={txtDatabaseName.Text.Trim()};
                                            User Id={txtLogin.Text.Trim()};Password={txtPassword.Text.Trim()};";
            var response = IsServerConnected(connectionString);
            if (response.isConnected)
            {
                lblConnectionState.Text = "✔";
                txtSqlConnectionError.Text = "";
            }
            else
            {
                lblConnectionState.Text = "❌";
                txtSqlConnectionError.Text = response.sqlErrorMessage;
            }
public static class SqlConnectionExtension
{
    #region Public Methods

    public static bool ExIsOpen(this SqlConnection connection, MessageString errorMsg)
    {
        if (connection == null) return false;
        if (connection.State != ConnectionState.Open)
        {
            try
            {
                connection.Open();
            }
            catch (Exception ex) { errorMsg.Append(ex.ToString()); }
        }
        return true;
    }

    public static bool ExIsReady(this SqlConnection connction, MessageString errorMsg)
    {
        if (ExIsOpen(connction, errorMsg) == false) return false;
        try
        {
            using (SqlCommand command = new SqlCommand("select 1", connction))
            using (SqlDataReader reader = command.ExecuteReader())
                if (reader.Read()) return true;
        }
        catch (Exception ex) { errorMsg.Append(ex.ToString()); }
        return false;
    }

    #endregion Public Methods
}



public class MessageString : IDisposable
{
    #region Protected Fields

    protected StringBuilder _messageBuilder = new StringBuilder();

    #endregion Protected Fields

    #region Public Constructors

    public MessageString()
    {
    }

    public MessageString(int capacity)
    {
        _messageBuilder.Capacity = capacity;
    }

    public MessageString(string value)
    {
        _messageBuilder.Append(value);
    }

    #endregion Public Constructors

    #region Public Properties

    public int Length {
        get { return _messageBuilder.Length; }
        set { _messageBuilder.Length = value; }
    }

    public int MaxCapacity {
        get { return _messageBuilder.MaxCapacity; }
    }

    #endregion Public Properties

    #region Public Methods

    public static implicit operator string(MessageString ms)
    {
        return ms.ToString();
    }

    public static MessageString operator +(MessageString ms1, MessageString ms2)
    {
        MessageString ms = new MessageString(ms1.Length + ms2.Length);
        ms.Append(ms1.ToString());
        ms.Append(ms2.ToString());
        return ms;
    }

    public MessageString Append<T>(T value) where T : IConvertible
    {
        _messageBuilder.Append(value);
        return this;
    }

    public MessageString Append(string value)
    {
        return Append<string>(value);
    }

    public MessageString Append(MessageString ms)
    {
        return Append(ms.ToString());
    }

    public MessageString AppendFormat(string format, params object[] args)
    {
        _messageBuilder.AppendFormat(CultureInfo.InvariantCulture, format, args);
        return this;
    }

    public MessageString AppendLine()
    {
        _messageBuilder.AppendLine();
        return this;
    }

    public MessageString AppendLine(string value)
    {
        _messageBuilder.AppendLine(value);
        return this;
    }

    public MessageString AppendLine(MessageString ms)
    {
        _messageBuilder.AppendLine(ms.ToString());
        return this;
    }

    public MessageString AppendLine<T>(T value) where T : IConvertible
    {
        Append<T>(value);
        AppendLine();
        return this;
    }

    public MessageString Clear()
    {
        _messageBuilder.Clear();
        return this;
    }

    public void Dispose()
    {
        _messageBuilder.Clear();
        _messageBuilder = null;
    }

    public int EnsureCapacity(int capacity)
    {
        return _messageBuilder.EnsureCapacity(capacity);
    }

    public bool Equals(MessageString ms)
    {
        return Equals(ms.ToString());
    }

    public bool Equals(StringBuilder sb)
    {
        return _messageBuilder.Equals(sb);
    }

    public bool Equals(string value)
    {
        return Equals(new StringBuilder(value));
    }

    public MessageString Insert<T>(int index, T value)
    {
        _messageBuilder.Insert(index, value);
        return this;
    }

    public MessageString Remove(int startIndex, int length)
    {
        _messageBuilder.Remove(startIndex, length);
        return this;
    }

    public MessageString Replace(char oldChar, char newChar)
    {
        _messageBuilder.Replace(oldChar, newChar);
        return this;
    }

    public MessageString Replace(string oldValue, string newValue)
    {
        _messageBuilder.Replace(oldValue, newValue);
        return this;
    }

    public MessageString Replace(char oldChar, char newChar, int startIndex, int count)
    {
        _messageBuilder.Replace(oldChar, newChar, startIndex, count);
        return this;
    }

    public MessageString Replace(string oldValue, string newValue, int startIndex, int count)
    {
        _messageBuilder.Replace(oldValue, newValue, startIndex, count);
        return this;
    }

    public override string ToString()
    {
        return _messageBuilder.ToString();
    }

    public string ToString(int startIndex, int length)
    {
        return _messageBuilder.ToString(startIndex, length);
    }

    #endregion Public Methods
}

Почему бы просто не подключиться к сеансу Telnet на порт сервера SQL. Если он подключается, сервер sql работает и счастлив, если нет, вам не повезло.

Этот другой пост Stackru может быть хорошим началом для этого.

РЕДАКТИРОВАТЬ: ОК, теперь я полностью прочитал другие сообщения, это не совсем лучшее решение... Тем не менее, если вы просто хотите пинговать порт....

Похоже на ответ, предложенный Андреем, но я использую:

Выберите GetDate() в качестве CurrentDate

Это позволяет мне увидеть, есть ли у SQL Server и клиента какие-либо проблемы с разницей во времени, в одном действии.

Обычно я делаю это, открывая соединение, но у меня были случаи, когда простой тест через Open вызвал AccessViolationException

      using (SqlConnection db = new SqlConnection(conn))
{    
  db.Open(); // -- Access Violation caused by invalid Server in Connection String
}

Итак, я сделал проверку TCP перед открытием, как рекомендовал Джоэл Кохорн. Код C # для этого может быть:

      string targetAddress = "";
try
{
  targetAddress = GetServerFromConnectionString();
  IPAddress ipAddress = Dns.GetHostEntry(targetAddress).AddressList[0];
  IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 1433);

  using (TcpClient tcpClient = new TcpClient())
  {
       tcpClient.Connect(ipEndPoint);           
  }
            
}
catch (Exception ex)
{
    LogError($"TestViaTcp to server {targetAddress} failed '{ex.GetType().Name}': {ex.Message}");
}

Вот моя версия, основанная на ответе @peterincumbria:

      using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return await dbContext.Database.CanConnectAsync(cToken);

Я использую Observable для опроса проверки работоспособности по интервалу и обработки возвращаемого значения функции. try-catch здесь не требуется, потому что:

Подключение к mssql через C# очень проблематично.

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

Я где-то читал, что это проблема.Net 4.0, и если вы используете.Net 3.5, все должно быть в порядке.

Другие вопросы по тегам