SqlConnection timeout oddities - c#

I am experiencing a weird issue where the timeout remaining for a connection attempt seems to be persisting through multiple attempts.
I have a simple window where connection information is entered, with a connect and cancel button.
When the user hits connect, the following code executes:
DisableControls();
if((bool)AutoAuthenticated.IsChecked)
{
((MainWindow)Owner).myConnection = new System.Data.SqlClient.SqlConnection
("server="+ServerName.Text + ";"+
"Trusted_Connection=yes;" +
"database="+DatabaseName.Text + ";" +
"connection timeout=3");
}
else
{
((MainWindow)Owner).myConnection = new System.Data.SqlClient.SqlConnection
("user id="+UserName.Text+";" +
"password="+Password.Password+";" +
"server="+ServerName.Text+";" +
"Trusted_Connection=no;" +
"database="+DatabaseName.Text+";" +
"connection timeout=3");
}
await ConnectToServer();
This is the ConnectToServer function:
private async Task ConnectToServer()
{
//using (((MainWindow)Owner).myConnection)
//{
await ((MainWindow)Owner).myConnection.OpenAsync();
//}
}
The timeout property is small right now for the purposes of testing.
Anyway, if the user hits the cancel button whilst connecting:
private void Cancel_Click(object sender, RoutedEventArgs e)
{
if (((MainWindow)Owner).myConnection != null &&
((MainWindow)Owner).myConnection.State ==
System.Data.ConnectionState.Connecting)
{
((MainWindow)Owner).myConnection.Close();
EnableControls();
}
else
{
this.Close();
}
}
Now, if I enter in bogus details and leave it to timeout, then I catch the exception with 'The network path was not found.'.
If I try and connect again after this (or maybe the one after the next attempt depending on how quick I was to hit the cancel button), it times out almost instantly after hitting the connect button, without waiting the amount of time it was supposed to.
I'm not sure what I'm doing wrong here, I've tried looking in to resetting the SqlConnection object, but I thought the setting of it to a new SqlConnection each time I hit connect should be doing this already?

I found out what I was missing. Even when closing the connection, disposing of the object, keeping it all in a using statement, the issue persisted because there was another element that I was unaware of - the connection pool.
I still have to do some reading on this, but basically it reuses old connection information and so on to save on resources, etc.
There's more information here, but in case this helps someone else with similar issues, just call the ClearPool() function when you close the connection:
Example (in my exception handling code, and after I call Close()):
System.Data.SqlClient.SqlConnection.ClearPool(((MainWindow)Owner).myConnection);
Obviously from a resource usage perspective, it would probably be best to call that function only when you don't need to reuse the connection, but that said, I still need to read up on this so don't take my word for it!

Related

Handle connection to MySql lost

I would like to detect connection state to MySql database. My database is deployed in different server than my app and there is good chances to lose connection to it via network. So I have to take this scenario into consideration.
Here is what I tried so far (a simplified test example):
static string connectionString = "***";
public static MySqlConnection Connection;
static System.Timers.Timer _timer;
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
if (Connection.State != System.Data.ConnectionState.Open)
Connection.Open();
// Call method to invoke MySqlCommand.ExecuteNonQuery
mysqlCommand.ExecuteNonQuery();
}
catch (MySqlException ex)
{
Console.WriteLine("SQL EXCEPTION: " + ex);
// Handle all type of database exceptions
switch(ex.Number)
{...}
}
catch (Exception ex)
{
Console.WriteLine("OTHER EXCEPTION: " + ex);
}
}
static void Main(string[] args)
{
Connection = new MySqlConnection(connectionString);
_timer = new System.Timers.Timer(3000);
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
Console.ReadKey();
}
If the connection to MySql is lost, I got a general exception:
IOException : Unable to write data to the transport connection: An
established connection was aborted by the software in your host
machine.
I was expecting MySqlException to be fired but that was not the case.
Also, if the connection to MySql is restored, I still get the IOException instead of executing the query. Seems like, MySqlConnection object has not been updated and it doesn't care about new connection state.
What's the best way to handle connection lost exception?
How can I refresh MySqlConnection when connection is restored?
Note: that I can't instantiate a new MySqlConnection object for each new query, because the program I'm trying to change has a Singleton of type MySqlConnection which is initialized only once. I know that's a bad design but I don't want to change this design now. I just want to catch connection lost exception and try to refresh MySqlConnection to continue to work correctly.
If your MySqlConnection instance loses its connection to your MySQL server, you cannot expect that instances's connection to be restored automatically or otherwise.
You need to try to reconnect with a new instance of MySqlConnection. The one that has lost the connection is now in a terminal state and cannot be reused.
To do this, I suppose you could do something like this
...
catch (MySqlException ex)
{
if (/*ex is a connection drop */) {
Connection?.Dispose();
Connection = new MySqlConnection(...);
Connection.ConnectionString = /* your connection string */;
Connection.Open();
}
else {
throw;
}
}
You are correct that your design has a flaw. Whether or not your flaw is fatal is hard to tell without testing.
These Connection instances are not thread safe or in any way reentrant. If you use one in a timer handler or thread, you may only use it in that context. Otherwise, if it's already in use when your timer or thread is invoked, things will get dicey. If you're lucky you'll get an exception. If you're less lucky your MySQL server will receive gibberish from your client and detect it. If you're even less lucky your data will get scrambled up.
ADO.NET and the MySqlConnection object implement connection pooling. This matters because it makes opening connections, using them, and then closing them, a lot cheaper than you might have expected.
Sometimes MySQL drops connections that your programs have held open for long periods of time. This post may help if that is your problem.
How can I change the default Mysql connection timeout when connecting through python?
When you lost your connection by networks problems, the connection object does not change Status property so evaluate it before executting commands doesn't work.
However, the database property (connection.database) goes to empty string so you can evaluate it so can close the connection an restores it:
oConn is an instance of MySQLConnection (it works on odbcconnection)
[VB.NET]
If Not IsNothing(oConn) Then
If (oConn.Database.Equals(String.Empty)) Then oConn.Close()
End If
[C#]
If (Not IsNothing(oConn)){
If (oConn.Database.Equals(String.Empty)) oConn.Close();
}

Disabled SQL connection claims to be open C#

A number of discussions like this are treating how to check if a SQL connection is open, using the ConnectionState enum. Recently I have experienced that a ConnectionState.Open may not always tell the truth in .NET 2.0.
If the connection is broken from outside while my C# application is running, the connection state is not updated. Since it still claims that the connection is open, I can not use the following assurance method:
if(Something_Connection.State != ConnectionState.Open)
{
Something_Connection.Close();
Something_Connection.Open();
}
The issue may be reproduced using the following test. Assuming that you initially have an open connection m_dbConnection and a working command line method CommandLineUtils.Run(...):
[Test]
public void ConnectionStateDoesNotLie()
{
// Close SQL service:
Console.WriteLine(CommandLineUtils.Run("net", "stop \"SQL Server (MSSQLSERVER)\"", 10));
System.Threading.Thread.Sleep(500);
// Check state:
bool stateIsCorrect = m_dbConnection.ConnectionState != ConnectionState.Open;
// Finished testing, restart the SQL service:
Console.WriteLine(CommandLineUtils.Run("net", "start \"SQL Server (MSSQLSERVER)\"", 30));
Assert.IsTrue(stateIsCorrect, "Connection state of closed connetion claims to be open.");
}
My question is if there is a better method to check if a connection has been broken? Prior to running a query.
Of cause I could run every query in a try-catch and then try to reopen the connection if an exception is thrown. But this seems like a clumsy solution. I also want to avoid running any dummy update to test the connection prior to every query in my program.
(Why would I want to stop my SQL service during runtime? I would not, but people using my program may sometimes leave it open for 5 hours and then come back expecting it to work. Sometimes their connection may have failed during this period)
The solution to this problem is to disable connection pooling. For example (I'm using PowerShell here, but it's the same for any other .NET language), using a disabled user named U with a password PW on a server S:
$conn = [System.Data.SqlClient.SqlConnection]::new("server=S;user id=U;password=PW")
$conn.Open(); #Throws no exception, reports connection state of Open
$conn = [System.Data.SqlClient.SqlConnection]::new("server=S;user id=DU;password=PW;Pooling=False")
$conn.Open(); #Throws an exception
I'd recommend this pattern: Get the SQL task request, Open the connection, perform the task, Close the connection, respond to the results.
Replace m_dbConnection with m_dbConnectionString.
Your app will be more reliable and any time you need to restart SQL, you won't have a ton of "are you sure -- there are 20 people connected" messages.
Thanks for your comments and answers, I will keep your pattern in mind for future reference, #Dustin_00.
However in this special case I forgot to specify that the application in view is a database API. Therefore the responsibility for opening and closing connections should be forwarded to the programs integrating it, as one sometimes would desire to perform a number of operations on the same connection. But I want to make the API more invulnerable to errors concerning lost connections.
Since this is the case, and no answers concerning a non-lying connection.State test could be found, I landed on the solution mentioned as an option in my question. Where the API performs an extra try, if the query for some reason fails. Preferably I would like a trustworthy solution similar to
if (Connection.State != ConnectionState.Open){}.
For others running into the same issue without possibility to avoid it, an example wrapper method is provided here:
/// <summary>
/// Wrapper method for OdbcCommand.ExecuteScalar, trying to open connection if the first attempt fails
/// </summary>
/// <param name="readyCommand"></param>
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns>
internal static object ExecuteScalar(OdbcCommand readyCommand, bool throwExceptions)
{
if (readyCommand == null)
return -1;
object retVal;
try
{
retVal = readyCommand.ExecuteScalar();
}
catch (Exception e)
{
if (readyCommand.Connection != null)
{
try
{
// Try reopening connection and retry;
readyCommand.Connection.Close();
readyCommand.Connection.Open();
retVal = readyCommand.ExecuteScalar();
}
catch (Exception)
{
if (throwExceptions)
throw e; // rethrow the original exception
retVal = null;
}
}
else
{
if (throwExceptions)
throw e; // rethrow the original exception
retVal = null;
}
}
return retVal;
}

How can I circument the "80004005 There is a file sharing violation...." err msg on a SQL Server CE database?

I am getting error
80004005 There is a file sharing violation. A different process might be using the file.
when trying to open a SqlCeConnection.
Is there a way to close a SQL Server CE database programmatically, to try to nip that problem in the bud? Something like (pseudocode):
SqlCeDatabase SQLCeDb = "\My Documents\HHSDB003.sdf";
if (SQLCeDb.IsOpen)
{
SQLCeDb.Close();
}
?
Or a way to set the connection so that it doesn't care if the database is open elsewhere/wise, such as:
SqlCeConnection conn = new SqlCeConnection(#"Data Source=\My Documents\HHSDB003.sdf;File Mode = 'shared read'");
...or:
SqlCeConnection conn = new SqlCeConnection(#"Data Source=\My Documents\HHSDB003.sdf;File Mode = 'read write'");
I can't test these at present, because I'm back to getting
Cannot copy HHS.exe The device has either stopped responding or has been disconnected
when I attempt to copy over a new version of the .exe to the handheld.
If there's something more frustrating to program against (and "against" is the correct word here, I think) than the prehistoric versions of Windows CE / Compact Framework / .NET, I'm not at all sure I want to know what it is.
UPDATE
Adding to my frustrusion (haywire combination of confusion and frustration), I found the following at http://www.pocketpcfaq.com/faqs/activesync/exchange_errors.php:
0x80004005 N/A Synchronization failed due to a device software error. Contact your network administrator.
1. Obtain the latest Pocket PC End User Update from your service provider.
UPDATE 2
Is this possibly problematic (than all but the first setting is blank):
UPDATE 3
With this code:
private void menuItemTestSendingXML_Click(object sender, System.EventArgs e)
{
string connStr = "Data Source=My Documents\\HHSDB003.SDF";
SqlCeConnection conn = null;
try
{
try
{
conn = new SqlCeConnection(connStr);
conn.Open();
MessageBox.Show("it must have opened okay");
}
finally
{
conn.Close();
}
}
catch (Exception ex)
{
if (null == ex.InnerException)
{
MessageBox.Show("inner Ex is null");
}
MessageBox.Show(String.Format("msg is {0}", ex.Message));
}
}
...I am now seeing "it must have opened okay" (that's a good thing, but...why it's now working, I have no idea, because the code has not changed since I last ran it and it failed. Something beyond the code must have been at play.
The only thing I can think of that happened that MAY have had a bearing on this change is that, thinking there may have been a rogue instance of either the .exe or its ancillary dll in memory on the handheld device, I wrote an quick-and-dirty utility that looped through the running processes, looking for them and, if finding them, killing them, but they were not there, so the utility really did "nothing" (maybe the Hawthorne effect?).
That is the way working with this combination of tools and technologies seems to go, though: everything is working fine one minute and the next, BAM! It no longer is. Then the reverse can also happen: for no apparent reason it seems to "heal itself".
In the interests of "full disclosure," here is the utility code:
// Got this from http://www.codeproject.com/Articles/36841/Compact-Framework-Process-class-that-supports-full
private void btnKillRogue_Click(object sender, EventArgs e)
{
ProcessInfo[] list = ProcessCE.GetProcesses();
foreach (ProcessInfo item in list)
{
MessageBox.Show("Process item: " + item.FullPath);
if (item.FullPath == #"\Windows\iexplore.exe") item.Kill(); //<= this was the example search; it probably could be a problem, so I'll use it, too
if (item.FullPath.EndsWith("HHS.exe"))
{
MessageBox.Show("about to kill hhs.exe");
item.Kill();
}
if (item.FullPath.EndsWith("HUtilCE.dll"))
{
MessageBox.Show("about to kill hutilce.dll");
item.Kill();
}
}
}
Maybe there was an instance of iexplore.exe resident in memory that was problematic (I'm not showing a messagebox if that is what is found)...?
As an attempt to claim unused bounty ... do not, however, feel obligated to pass around free points on my behalf ...
Aside from force killing of possible tasks, had you rebooted the system amidst your search for an answer? If your tool did not return the message, it is certainly possible that a reboot would have done the very thing that you had attempted with the kill utility - or possible iexplore.exe had something to do with it ... the lack of the additional messagebox may leave you never knowing - unless this issue occurs again.
If no rebooting occurred, then perhaps whatever program/dll was held in memory by some other process concluded its task and released it hold.
There are several scenarios that might have occurred, it is certainly hard to determine with absolution; hence the lack of answers. I would be interested, though, if this problem occurred again.

How to handle database exceptions/ issue?

I one of my c# application, i have written sql connection code as following
try
{
myConnection = new SqlConnection(m_resourceDB.GetResourceString(nSiteID, ApplicationID.XClaim,(short)nResID ) );
myConnection.open();
}
I want to handle unkown issue of sqlserver like database down, time out.
For this i though to introduce for loop 3 times with 3 minute sleep between loop and if at all problem is there then i will exit from loop
I don't know my though is right or not? I want some expert advice on this? Any example?
I would say simply: the code that talks to connections etc should not be doing a sleep/retry, unless that code is already asynchronous. If the top-level calling code wants to catch an exception and set up a timer (not a sleep) and retry, then fine - but what you want to avoid is things like:
var data = dal.GetInfo();
suddenly taking 3 minutes. You might get away with it if it is an async/callback, and you have clearly advertised that this method may take minutes to execute. But even that feels like a stretch. And if you are up at the application logic, why not just catch the exception the first time, tell the user, and let the user click the button again at some point in the future?
If you are running a service with no user interface, then by all means, keep on looping until things start working, but at least log the errors to the EventLog while you're at it, so that the server admin can figure out when and why things go wrong.
For a client application, I would no suggest that you make the user wait 9 minutes before telling them things are not working like they should. Try to connect, assess the error condition, and let the user know what is going wrong so that they can take it further.
If you are using the SqlException class you can check the Exception Class and decide based on that what is going wrong, for example:
switch (sqlEx.Class)
{
case 20:
//server not found
case 11:
//database not found
All the classes have the SQL Server message on them, it is a matter of testing the different conditions.
It really depends on how you want your application to behave.
If your database access is dealt with on the same thread as your UI then whilst you are attempting to connect to a database it will become unresponsive.
The default time period for a connection timeout is already pretty long and so running it in a for loop 3 times would triple that and leave you with frustrated users.
In my opinion unless your specifically attempting to hide connection issues from the user, it is by far better to report back that a connection attempt has failed and ask the user if they wish to retry. Then having a count on the number of times that you'll allow a reconnection attempt before informing the user that they can't continue or putting the application into an "out of service" state.
I want to handle unkown issue of sqlserver like database down, time out.
Try to surround connection operation with using statement to capture connection related problems .
using( sqlcon = new SqlConnection(constr))
{}
Use the Try/Catch Statement for capturing the exception:
try
{
con.Open();
try
{
//Execute Queries
// ....
}
catch
{
// command related or other exception
}
finally
{
con.Close();
}
}
catch
{
// connection error
}
To prevent Exception of such type check these:
Troubleshooting Timeout SqlExceptions
you can set the CommandTimeout to some value on a SqlCommand:
objCmd.CommandTimeout = 600
You can catch the SqlException.
SqlException.Class
Gets the severity level of the error returned from the .NET Framework Data Provider for SQL Server.
SqlException.Errors
Gets a collection of one or more SqlError objects that give detailed information about exceptions generated by the .NET Framework Data Provider for SQL Server.
SqlCommand cmd = new SqlCommand();
cmd.Connection = new SqlConnection("CONNECTION_STRING");
cmd.CommandText = "SELECT * FROM ....";
// cmd.CommandType = System.Data.CommandType.Text;
try
{
cmd.Connection.Open();
try
{
SqlDataReader reader = cmd.ExecuteReader();
// ....
}
finally
{
cmd.Connection.Close();
}
}
catch (SqlException ex)
{
// ex.Class contains the ErrorCode, depends on your dataprovider
foreach (SqlError error in ex.Errors)
{
// error.LineNumber
// error.Message
}
}
The best way would be to putt it in a try catch statement and display the error in a better format, If it fails for 1 time, trying it continue sly 3 times will not change anything untill and unless you dc and send request again, In a separate in separate packed as a new request.
use try this.
try
{
Executing code.
}
catch (Exception err)
{
Display["ErrorMsg"] = err.Message.ToString() + "|" + err.GetBaseException() + "|" + Request.Url.ToString();
}
Good Luck.

Most effective way to connect/retry connecting using C#?

I am creating a little game client that will end up connecting to a server to gather some information on available games to play, how many players are playing, and all kinds of other stuff that you can imagine it ought to do.
My difficulties come in finding an effective way in dealing with the connect/retry connect sequence upon first loading.
I imagined my client would follow this process in trying to connect:
Client application executed
Try to establish connection
If connection successful gather information - If not successful proceed to step 4
Display a new dialog/form that prompts the user that a connection is trying to be established
Loop till a connection has been established
I have been questioning my methods in trying to follow this sequence. I question if it is the right/most effective way to connect as well as to why my form I display in step 4 isn't working?
try
{
sock.Connect(authenServerEP);
// Once connected show our main client window
this.Show();
// Create the LoginForm once a connection has been established and display
LoginForm loginForm = new LoginForm();
loginForm.ShowDialog();
if (false == loginForm.Visible)
{
loginForm.Dispose();
}
}
catch (SocketException firstConnectException)
{
// Load retrying connection form
EstablishingConnectionForm establishingConnectionForm = new EstablishingConnectionForm();
establishingConnectionForm.Show();
bool connected = false;
// Loop until we are connected
while (!connected)
{
try
{
sock.Connect(authenServerEP);
connected = true;
establishingConnectionForm.Dispose();
}
catch (SocketException retryConnectException)
{
// Pass and retry connection
}
}
} // end catch (SocketException firstConnectException)
As you can see I am catching the SocketException that is raised when there is a problem connecting to the server (such as the server isn't running). I then go on to try to continuously loop till a connection is established. I dunno if I ought to be doing it this way. Are there better ways to do this?
Also when I display establishingConnectionForm with Show() it doesn't look like it all of the forms/tools initialize (initialize could be misleading). The Label that is on the form is just shaded out in white as opposed to having its text displayed. Not only that but it seems like I can't select the form/dialog and actually move it around. It sits there with the "Thinking/Working" mouse icon. Now I presume this is because I am looping trying to reconnect and its blocking because of this (I could be wrong on the blocking?). Can this problem be solved with multithreading? If so do I need to multithread? Is there an easier way to show my form/dialog and be able to interact (IE movie it around and close it with the 'X' in the upper right corner) with it while I still try to reconnect?
Thanks a bunch. I really appreciate you reading this post and am grateful for this community. :D
Just an example below where I would handle any continuation logic in the catch and either break out or continue inside the while loop.
Andrew
while (!connected)
{
try
{
sock.Connect(authenServerEP);
connected = true;
establishingConnectionForm.Dispose();
}
catch (SocketException retryConnectException)
{
//Optional - add some wait time may be 5 seconds i.e. "trying again in 5 seconds"
//System.Threading.Thread.Sleep(5000);
//Here check the number of attempts and if exceeded:
if(numberOfTimes == 5)
{
break;
}
else
{
numberOfTimes++;
continue;
}
}
}

Categories

Resources