S
steinmr
I have a need for a SqlConnection.Open that times out in an
predictable matter (i.e. if the server does not answer, I do not have
to wait for TCP or NIC timeouts to find out). The "Connection Timeout"
in the connectionstring will not help, as this only applies to the
connection to the SQL Server, not to the actual TCP port.
Therefore I have had a crack at it myself, and would appreciate any
constructive comments on the implementation. The method
BeginOpen(SqlConnection,int) will take an SqlConnection and a timeout
(in ms), and will try to open it. If it for any reason cannot, it will
return within the specified timeout. If there is an exception in
connection before the timeout occurs, it will throw that, otherwise it
will throw a custom Exception.
There is an 4-5 ms overhead by doing this, but I'm willing to
sacrifice this for a predictable timeout.
Any comments appreciated...
private void BeginOpen(SqlConnection connection, int msTimeout)
{
// Start timeout timer here, it includes all work done in this
method.
// This assures that this method uses no more than msTimeout to
complete
DateTime connectionAbortTime =
DateTime.Now.AddMilliseconds(msTimeout);
// Transfer ambient transaction to thread
Transaction currentTransaction = Transaction.Current;
// Save the thread exception (if any)
Exception threadException = null;
// Signifies that we could connect and communicate with the database
bool connectSuccess = false;
Thread workerThread = new Thread(
delegate()
{
try
{
Transaction.Current = currentTransaction;
connection.Open(); // This might hang indefinatly
connection.ChangeDatabase(connection.Database);
connectSuccess = true;
}
catch (Exception ex)
{
threadException = ex;
}
}
);
workerThread.IsBackground = true; // Make sure application tears it
down when it exits
workerThread.Name = "SqlConnection.BeginOpen";
// Start work and wait for the thread to finish or it times out
workerThread.Start();
while (connectionAbortTime > DateTime.Now)
if (workerThread.Join(1)) // Check if thread is finished
break;
// For some reason, the connection could not be opened, throw an
exception
if (!connectSuccess)
{
if (threadException != null) // Encountered an exception before
timeout
throw threadException;
else // Either timed out OR did not have time to save exception in
threadException
throw new SqlConnectionTimeoutException("Could not connect to
server within timeout");
}
}
public class SqlConnectionTimeoutException : Exception
{
public SqlConnectionTimeoutException(string message) : base(message)
{}
}
predictable matter (i.e. if the server does not answer, I do not have
to wait for TCP or NIC timeouts to find out). The "Connection Timeout"
in the connectionstring will not help, as this only applies to the
connection to the SQL Server, not to the actual TCP port.
Therefore I have had a crack at it myself, and would appreciate any
constructive comments on the implementation. The method
BeginOpen(SqlConnection,int) will take an SqlConnection and a timeout
(in ms), and will try to open it. If it for any reason cannot, it will
return within the specified timeout. If there is an exception in
connection before the timeout occurs, it will throw that, otherwise it
will throw a custom Exception.
There is an 4-5 ms overhead by doing this, but I'm willing to
sacrifice this for a predictable timeout.
Any comments appreciated...
private void BeginOpen(SqlConnection connection, int msTimeout)
{
// Start timeout timer here, it includes all work done in this
method.
// This assures that this method uses no more than msTimeout to
complete
DateTime connectionAbortTime =
DateTime.Now.AddMilliseconds(msTimeout);
// Transfer ambient transaction to thread
Transaction currentTransaction = Transaction.Current;
// Save the thread exception (if any)
Exception threadException = null;
// Signifies that we could connect and communicate with the database
bool connectSuccess = false;
Thread workerThread = new Thread(
delegate()
{
try
{
Transaction.Current = currentTransaction;
connection.Open(); // This might hang indefinatly
connection.ChangeDatabase(connection.Database);
connectSuccess = true;
}
catch (Exception ex)
{
threadException = ex;
}
}
);
workerThread.IsBackground = true; // Make sure application tears it
down when it exits
workerThread.Name = "SqlConnection.BeginOpen";
// Start work and wait for the thread to finish or it times out
workerThread.Start();
while (connectionAbortTime > DateTime.Now)
if (workerThread.Join(1)) // Check if thread is finished
break;
// For some reason, the connection could not be opened, throw an
exception
if (!connectSuccess)
{
if (threadException != null) // Encountered an exception before
timeout
throw threadException;
else // Either timed out OR did not have time to save exception in
threadException
throw new SqlConnectionTimeoutException("Could not connect to
server within timeout");
}
}
public class SqlConnectionTimeoutException : Exception
{
public SqlConnectionTimeoutException(string message) : base(message)
{}
}