97

I need to develop a single routine that will be fired each 5 minutes to check if a list of SQL Servers (10 to 12) are up and running.

Is there a way to simply "ping" a SQL Server from C# one with minimal code and sql operational requirements?

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
backslash17
  • 5,300
  • 4
  • 31
  • 46
  • 2
    Simply pinging the server wouldn't be enough, it's possible for the server to be running but the SQL instance to be stopped. Creating an actual ado.net connection to the instance is the best option. – Rory Mar 13 '10 at 21:26
  • 2
    As you know there is a big difference between MS-SQL and SQL-server, specially if we are talking about ports and pinging them. What a democracy, everybody has to use the same tag. No options! You should add another tag no problem with that, but why to take out the one I choose!!!! – backslash17 Mar 13 '10 at 21:55
  • 2
    MS-SQL **IS** SQL Server - the product name **IS** SQL Server. – marc_s Mar 13 '10 at 21:56
  • 11
    SQL Server may refer to: - Any database server that implements the Structured Query Language - Microsoft SQL Server, a specific implementation database server from Microsoft - Sybase SQL Server, a relational database server developed by Sybase. ------- As you can see there are more than one meaning for SQL server and that's why I used the MSSQL tag – backslash17 Mar 14 '10 at 00:51
  • 2
    @backslash17 yes, and while true; if you `mouse over` the `sql-server` tag you will see it is Microsoft specific. I also say mssql and mysql etc... – NappingRabbit Jun 27 '18 at 10:32
  • Bit late, but shouldn't mssql be aliased to sql-server? – vikarjramun Jun 14 '20 at 04:34

11 Answers11

105

I have had a difficulty with the EF when the connection the server is stopped or paused, and I raised the same question. So for completeness to the above answers here is the code.

/// <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;
        }
    }
}
usr
  • 168,620
  • 35
  • 240
  • 369
27k1
  • 2,212
  • 1
  • 22
  • 22
  • 15
    no need for the `connection.Close();` in this case, the `using` clause will do it for you upon termination. –  Jul 13 '13 at 00:18
  • 4
    You should put the try catch outside of the using statement. (http://stackoverflow.com/q/4590490/1248177 or http://stackoverflow.com/q/6145245/1248177). – aloisdg Jan 08 '15 at 09:45
  • 1
    @aloisdg - It depends doesnt it, Are they testing to see if they can connect to a database and only in the exceptional circumstances they can not, they return false. OR do the want so swallow exceptions to do with constructing a SQL connection incorrectly too, I know there is a difference as I have just coded against the above. – brumScouse Jul 11 '17 at 15:22
89

Execute SELECT 1 and check if ExecuteScalar returns 1.

Andrew Bezzub
  • 15,744
  • 7
  • 51
  • 73
  • 1
    That's very good, no need to have any object created in a database, but I need to have a database and a user to make a query. I just want to know if the service is up in the MSSQL port. Anyway, you're solving almost 75% of the problem. This would be an option. – backslash17 Mar 13 '10 at 21:32
  • 6
    You have master db anyway :) The cleanest way to check if SQL Server is running is connect to it. To connect you need db and login anyway. All other solutions (like pinging SQL Server port) won't guarantee that SQL Server is running properly and anyone could connect to it. – Andrew Bezzub Mar 13 '10 at 21:55
  • I accidentally down-voted this answer while my real intention was to up-vote. I realized this one day after, so I cannot remedy my mistake any more. – Giorgos Betsos Feb 03 '19 at 08:32
  • 2
    @GiorgosBetsos - I fixed your mistake :-D – Kunal B. Jun 06 '20 at 12:38
15

See the following project on 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);
}
Geoffrey Huntley
  • 486
  • 1
  • 5
  • 11
7

Wouldn't establishing a connection to the database do this for you? If the database isn't up you won't be able to establish a connection.

Ken Henderson
  • 2,828
  • 1
  • 18
  • 16
  • Indeed, simply use ADO net to Connect - if there is no response within the timeout period then the database is not available. You don't need to issue a query to ascertain that. – Dan Diplo Mar 13 '10 at 21:21
  • To check with ADO.NET I need a user, I just want to check if the service is up and running, no problem about if a database is up. I need something like telnet an SMTP server. No need to have a user to obtain a response. – backslash17 Mar 13 '10 at 21:26
  • 3
    @backslash17: The "Login failed for user..." response should be enough to confirm that 1) the machine is up and 2) the service is running. If you get a connection timeout, then the service isn't running/working. – Rory Mar 13 '10 at 21:34
  • @Rory: Good point! Is just matter of checking the error in a try/catch block. Thanks! – backslash17 Mar 13 '10 at 21:40
  • @backslash17 Check that "Login failed for user" has separate error code or something that helps you to determine it. It is very bad practice to differ errors by exception message. – Andrew Bezzub Mar 13 '10 at 22:02
2

Look for an open listener on port 1433 (the default port). If you get any response after creating a tcp connection there, the server's probably up.


You know, I first wrote this in 2010. Today, I'd just try to actually connect to the server.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • For what Joel Coehorn suggested, have you already tried tcping [http://www.elifulkerson.com/projects/tcping.php]. It is a standalone executable which allows you to ping every specified time interval. It is not in C# though. Also..I am not sure If this would work If the target machine has firewall..hmmm.. – Ashish Gupta Mar 14 '10 at 09:01
2

For what Joel Coehorn suggested, have you already tried the utility named tcping. I know this is something you are not doing programmatically. It is a standalone executable which allows you to ping every specified time interval. It is not in C# though. Also..I am not sure If this would work If the target machine has firewall..hmmm..

[I am kinda new to this site and mistakenly added this as a comment, now added this as an answer. Let me know If this can be done here as I have duplicate comments (as comment and as an answer) here. I can not delete comments here.]

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Ashish Gupta
  • 14,869
  • 20
  • 75
  • 134
1
public static class SqlConnectionExtension
{
    #region Public Methods

    public static bool ExIsOpen(
        this SqlConnection connection, MessageString errorMsg = null)
    {
        if (connection == null) { return false; }
        if (connection.State == ConnectionState.Open) { return true; }

        try
        {
            connection.Open();
            return true;
        }
        catch (Exception ex) { errorMsg?.Append(ex.ToString()); }
        return false;
    }

    public static bool ExIsReady(
        this SqlConnection connction, MessageString errorMsg = null)
    {
        if (connction.ExIsOpen(errorMsg) == false) { return false; }
        try
        {
            using (var command = new SqlCommand("select 1", connction))
            { return ((int)command.ExecuteScalar()) == 1; }
        }
        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
}
Final Heaven
  • 124
  • 7
1

Thanks @27k1

https://stackoverflow.com/a/9943871/9479825

I have added some code here:

/// <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);
                }
            }
        }

Then call

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;
            }
0

Similar to the answer offered by Andrew, but I use:

Select GetDate() as CurrentDate

This allows me to see if the SQL Server and the client have any time zone difference issues, in the same action.

JustDaveN
  • 91
  • 6
0

Here is my version based on the @peterincumbria answer:

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

I'm using Observable for polling health checking by interval and handling return value of the function. try-catch is not needed here because: enter image description here

SerjG
  • 3,325
  • 3
  • 30
  • 30
0

I normally do this by open a connection but I had some cases where a simple test via Open caused a AccessViolationException

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

So I did a TCP check before the open like recommanded by Joel Coehoorn. C# Code for this may be:

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}");
}
Daniel W.
  • 938
  • 8
  • 21