SQL Server Connection Timeout argument passed doesn't work for a SqlConnection

qvtsj1bj  于 11个月前  发布在  其他
关注(0)|答案(9)|浏览(106)

I have the following connection string:

<add name="DatabaseServerInstance"
     providerName="Microsoft.Data.SqlClient"
     connectionString="Server=xx.xx.x.xx; Database=db; User Id=user; Password=pass; TrustServerCertificate=true; Connection Timeout=2;" />

I have a WPF with a control calling a MessageBox to show whether the connection to the database is established or not and I want Connection.Open() to terminate early instead of the user having to wait 15 seconds for the failed connection message to be displayed, but Connection Timeout=2 seems to do nothing.

An open connection gives an instantaneous response, while the failed connection despite the argument, loads with the average time no matter what the timeout is set to.

EDIT: This is the code for the sqlconnection call:

public class SqlPusher
{
    private static SqlCommand command = new SqlCommand();
    private static string connectionString = ConfigurationManager.ConnectionStrings["DatabaseServerInstance"].ConnectionString;

    public Boolean TestConnection()
    {
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            try
            {
                connection.Open();
                return true;
            }
            catch (SqlException)
            {
                return false;
            }
        }
    }

}

Debugger:

wnvonmuf

wnvonmuf1#

From what i saw in the ms code, the setting isn't really honored anywhere, so you need to use some other means to handle it, for example by wrapping your code in a thread and timing yourself (and therefor ignoring results of Connection.Open). Anyways, it's bad to use blocking methods like this inside GUI code.

See also https://github.com/dotnet/efcore/issues/10991 for discussion and workarounds to handle connection timeouts

myss37ts

myss37ts2#

There is several reason i think

first of all according to this use ConnectTimeout instead of Connection Timeout in the connection string.

second u can set the SqlConnection.ConnectionTimeout before opening the connection:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{
  connection.ConnectionTimeout = 2;
  
}

the last one u can call SqlConnection.OpenAsync() instead of Open() and pass a CancellationToken with a timeout this will abort the async open after 2 seconds :

using (SqlConnection connection = new SqlConnection(connectionString))
{

  CancellationTokenSource source = new CancellationTokenSource();
  source.CancelAfter(TimeSpan.FromSeconds(2));

  try 
  {
    await connection.OpenAsync(source.Token);
  
  }
  catch (OperationCanceledException)
  {
    // Handle timeout
  }

}
mtb9vblg

mtb9vblg3#

You could see what ConnectionTimeout means here: What is "Connect Timeout" in sql server connection string?

To achieve desired behaviour you have to send Timeout in SqlCommand (BUT it requires to use proper ConnectionString otherwise it won't work, see - CommandTimeout not working ) , so anyway you must provide ConnectionTime property in you conn str, or set it to 0 for indefinite wait and exit by exception:

SqlCommand cmd = new SqlCommand(cmdText, connection);
   cmd.CommandTimeout = 30;

After that you should execute you query i.e. insert/update/delete via cmd.ExecuteNonQuery , it internally uses timeout:

// inside ExecuteNonQuery method
this.InternalExecuteNonQuery((TaskCompletionSource<object>) null, nameof (ExecuteNonQuery), false, this.CommandTimeout, out bool _);
ddarikpa

ddarikpa4#

Try using the SqlConnectionStringBuilder class instead of a single string.

yeotifhr

yeotifhr5#

As a workaround you can introduce your own timeout:

int timeout = 1000;
var task = connection.OpenAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
    // task completed within timeout
} else { 
    // timeout logic
}

See this SO question for more details: Asynchronously wait for Task to complete with timeout

6za6bjd0

6za6bjd06#

I would do a fail fast approach using TcpClient , and then perform the actual SqlConnection for authentication

Here's my code:

public class SqlPusher
{
    private static SqlCommand command = new SqlCommand();
    private static string connectionString = ConfigurationManager.ConnectionStrings["DatabaseServerInstance"].ConnectionString;

    public Boolean TestConnection()
    {
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);

        #region quick-fail-test-using-tcp/sockets

        var server = builder.DataSource;
        var port = 1433; //default for sql server
        int TimeoutInMilliSeconds = 2000; //2 seconds

        if (server.Contains(',')) //parse "localhost,1433" into server & port
        { 
            var commaIndex = server.IndexOf(',');
            int.TryParse(server.Substring(commaIndex + 1), out port);
            server = server.Substring(0, commaIndex);
        }

        var tcpCheckPassed = false;
        try
        {
            using (var tcp = new System.Net.Sockets.TcpClient())
            {
                IAsyncResult result = tcp.BeginConnect(server, port, null, null);
                var connectResult = result.AsyncWaitHandle.WaitOne(TimeoutInMilliSeconds, true);
                if (connectResult && tcp.Connected)
                {
                    tcpCheckPassed = true;
                }
            }

        }
        catch (SocketException)
        {
            tcpCheckPassed = false;
        }

        if (!tcpCheckPassed)
            return false;  //tcp failed - no point continuing further.

        #endregion

        using (SqlConnection connection = new SqlConnection(builder.ToString()))
        {
            try
            {
                connection.Open();
                return true;
            }
            catch (SqlException)
            {
                return false;
            }
        }
    }

}
mec1mxoz

mec1mxoz7#

We have always used 30 as the default connection timeout in our apps in the connection string.
13 years ago someone asked the same question on Stack overflow as you have.

connection timeout property in connection string ignored

Seems 15 is the minimum and you are trying to set the value lower than 15 which won't work. One of the suggestions on above link is to try SqlConnectionStringBuilder

Since you have already tried it as suggested above by Signalist. May be try how it was suggested by Oppositional on the link I pasted here. They seemed to make it work.

vq8itlhq

vq8itlhq8#

change "connection timeout = 2" for "connect timeout = 2". That worked for me.

<add name="DatabaseServerInstance" 
     connectionString="Server=xx.xx.x.xx; Database=db; User Id=user; Password=pass; TrustServerCertificate=true; Connect Timeout=2;" />
jqjz2hbq

jqjz2hbq9#

Verify timeout expired errors When you encounter "timeout expired" issues, you receive one or more of the following error messages:

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

System.Data.SqlClient.SqlException (0x80131904): Connection Timeout Expired. The timeout period elapsed while attempting to consume the pre-login handshake acknowledgment. This could be because the pre-login handshake failed or the server was unable to respond back in time. The duration spent while attempting to connect to this server was [Pre-Login] initialization=23; handshake=14979; System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out.

System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out.

Connection Timeout Expired. The timeout period elapsed while attempting to consume the pre-login handshake acknowledgment. This could be because the pre-login handshake failed or the server was unable to respond back in time. The duration spent while attempting to connect to this server was [Pre-Login] initialization=21036; handshake=0; (Microsoft SQL Server, Error: -2).

System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.

相关问题