How to handle database exceptions/ issue? - c#

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.

Related

External component throws an exception

I have a question. I have Access Database and WPF application. The application is Build in 32-bit, and Access Database is 32-bit. And every once in a while the applications show me an error when connecting to database.. External component trows an exception. And eavn if I eat the error or try to connect to database again it doesn't work. I have to restart the application and then it works again until it throws and error again in next 15 or so database connection transaction. If you know what I mean.
How can I restart that error so I can again connect to database or eavn prevent the error from throwing.
Please help me.
I don't know what kind of code to provide that is relevant.
try
{
List<IDModel> output = new List<IDModel>();
using (OleDbConnection connection = new OleDbConnection(Conn))
{
await connection.OpenAsync();
using (OleDbCommand Command = new OleDbCommand("SELECT * FROM DATA WHERE [STATUS] = #status;", connection))
{
Command.Parameters.AddWithValue("#status", _status);
var reader = await Command.ExecuteReaderAsync();
while (reader.Read())
{
output.Add(InsertID
((int)reader["ID"], (string)reader["STANDARD"], (string)reader["NAZIV"], (string)reader["POSLOVNA ENOTA"],
(string)reader["IZVOR NESKLADNOSTI"], (string)reader["ODDELEK"], (string)reader["OPIS"],
(string)reader["SLIKA 1"].ToString(),
(string)reader["SLIKA 2"].ToString(), (string)reader["SLIKA 3"].ToString(), (string)reader["SLIKA 4"].ToString(),
(string)reader["SLIKA 5"].ToString(), (string)reader["EXCEL 1"].ToString(), (string)reader["PDF 1"].ToString(),
(string)reader["SLIKA 6"].ToString(), (string)reader["EXCEL 2"].ToString(), (string)reader["PDF 2"].ToString(),
(string)reader["KOREKCIJA"].ToString(),
(string)reader["SLIKA 7"].ToString(), (string)reader["EXCEL 3"].ToString(), (string)reader["PDF 3"].ToString(),
(string)reader["KOREKTIVNI"].ToString(), (string)reader["VZROK"].ToString(),
(string)reader["OCENA"].ToString(), (string)reader["OPOMBA"].ToString(),
(string)reader["NESKLADNOST ODPRL"].ToString(), (string)reader["KOREKCIJA PODAL"].ToString(), (string)reader["NESKLADNOST ZAPRL"].ToString(),
(string)reader["NESKLADNOST VALIDIRAL"].ToString(), (string)reader["ROK ZA REŠITEV"].ToString(),
(bool)reader["BIG EVENT"],
(string)reader["NESKLADNOST ODPRTA"].ToString(), (string)reader["KOREKCIJA PODANA"].ToString(),
(string)reader["NESKLADNOST ZAPRTA"].ToString(), (string)reader["NESKLADNOST VALIDIRANA"].ToString()
));
}
}
return output;
}
}
catch (Exception)
{
throw;
}
Best regards!
I would assume the problem is with the access database. In my experience, Access simply fail sometime, without apparent reason. I have spent quite a bit of time investigating access crashes without reaching a solution. There are some things that might help:
Ensure you are only ever using the database from a single thread.
Ensure all database related objects are correctly disposed.
Ensure the databases are not to large, there is a 2Gb limit on database size. Running compaction might help.
Add better error handling, catch errors and retry the operation. If repeated failures occur, dispose and recreate the database connection.
Move the database access to another process. This can help with error handling, allowing you to restart the entire process if needed.
My preferred solution is to avoid using access at all. Spend the time to port the data to some real database instead.

display DB connection on site

Just wondering if anyone knows how to display the status of a DB connection on a page.
I would like to know if there is a good connection, or if it is down. In this case I would also display the reason.
While working with database with asp.net, you connection shouldn't be open all the time. Keeping in this mind you dont have to (and shouldnt) display connection status of database all the time. What you should do is while performing queries with ado.net or another OR/M just capture SqlExceptions and provide meaningfull errors to your user.
From msdn article :
try {
// code here
}
catch (SqlException odbcEx) {
// Handle more specific SqlException exception here.
}
catch (Exception ex) {
// Handle generic ones here.
}
Just capture the db exception, cause it will fire an exception/error once there is no connection.
and if there is a connection, you would know
There could be many ways to check for connection status, You may use ASP.Net Timer to periodically check for the connection, (remember that each timer interval causes a postback to the server and causes network traffic ), See Walkthrough: Using the ASP.NET Timer Control with Multiple UpdatePanel Controls
In the Timer_Tick event, you may check for the connection and post a message in label. Something on the following lines...
protected void Timer1_Tick(object sender, EventArgs e)
{
try
{
using (SqlConnection sqlConn =
new SqlConnection("YourConnectionString"))
{
sqlConn.Open();
Label1.Text = "Database Available";
}
}
catch (Exception ex)
{
Label1.Text = "Database Un-Available, " + "Possible Reason:"+ ex.Message;
}
}
Its not a good practice to catch generic exception (Exception) , you may catch SQLException and then have another block to handle generic exception.
Ideally, it is not really a good practice to tell users about database. Any database error should be logged and replaced with a more user friendly error message.
If you still need to display connection state on the screen, you can handle the StateChange event for SQLConnection and display appropriate message.
Update: I would suggest that you just log the errors and have a program to send you emails with failures or manually look into the system rather than users telling you that your database is down.

Testing Database Connectivity in C# Console Application

I have a C# Console Application that is essentially a long batch process that processes data on a nightly basis across many different databases. What is the proper or preferred way to test basic database connectivity at the beginning of this type of program? I ran into the issue of having an expired database password for one of my connections that was caught by exception handling but I want to test for basic connectivity at the very beginning.
Would a simple SELECT query suffice or is there a more efficient way of doing this for numerous databases?
IMHO the simplest way is trying to connect to database and, if you have a failure, you give up.
As you're running a night batch, it's not important to understand immediately the reason and solve it.
So something like this
using(SqlConnection conn = new SqlConnection(connectionString))
{
try
{
conn.Open();
// Do what you please here
}
catch (Exception ex)
{
// Write error to file
File.Append(...,
DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + " " +
ex.Message);
}
finally
{
conn.Close();
}
}
Next morning you can check file for errors...
'Connection.open`
is the simple way to determine if you can connect to db or not.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
}
If you get a SqlException with number 18487 or 18488 it indicates the password has been changed.
Connection.changePassword
You don't need to run any query.
If you use SqlConnection passing the connection string, you can just try to Open() the connection and you'll get an exception if you cannot connect
Something like:
try
{
var cnn = new SqlConnection(connectionString);
cnn.Open();
}
catch
{
// connection failed, do something
}
Opening (and then closing) a connection should be sufficient to test the password. however, this does not tell you , if a db-user has permissions to access specific tables.

.Net Client Timeout

In my Windows application I try to connect to SQL Server 2008 with following code:
SqlConnection connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString);
SqlCommand command = new SqlCommand("Select IsAdmin from Users where UserName=#UserName And Password=#Password", connection);
SqlDataReader dataReader = null;
command.Parameters.AddWithValue("#UserName", UserNameTextBox.Text.Trim());
command.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
try
{
connection.Open();
dataReader = command.ExecuteReader();
if (dataReader.HasRows)
{
while (dataReader.Read())
{
IsAdmin = dataReader.GetBoolean(0);
}
this.DialogResult = DialogResult.OK;
}
else
{
FMessageBox.ShowWarning("error");
UserNameTextBox.Focus();
}
}
catch (Exception ex)
{
if (progressForm != null)
progressForm.Close();
FMessageBox.ShowError(ex.Message);
}
finally
{
if (dataReader != null)
{
dataReader.Close();
dataReader.Dispose();
}
if (connection != null)
{
connection.Close();
connection.Dispose();
}
}
Everything works properly, but sometimes I get the following error:
timeout expired. the timeout period elapsed prior to obtaining a
connection from the pool ...
How can this be solved?
The reason you're getting this exception is because you have exhausted your connection pool and the number of "available" connections in your application.
Every time you open a connection, one is pulled from the connection pool if possible, or a new one is created if not.
However, to prevent galloping usage of connections, a limit of 100 (I think this is configurable) exists, and if you try to use more than 100 simultaneous connections, the code will not create new ones, and instead sit down to wait for one to be returned to the pool, and in this case you get a timeout if it sits too long.
So, for the particular example of code you've shown, I would:
Close the connection before I show an error messages to the user
However, unless 100 users are seeing the error message and leaving it there at the same time, it is unlikely the code you've shown is the cause of this problem.
Other than that, I would go through the entire application and ensure you don't have any connection leaks other places.
This particular type of exception can occur in one spot even though the problem is somewhere else. Example: A report is leaking an open connection every time it runs, and you run it 100 times successfully, then someone tries to log in, and the exception occurs in the login form.
That happens if you either:
leak connections (leaving them for GC to deal with rather than disposing them)
just have too much happening, such that the pool is exhausted
The first is the most common, and I expect it relates a lot to the fact that you are over-complication your error handling. This makes it easy to miss, and hard to spot that you've missed it. The code shown looks OK, but it would be far preferable to use using blocks for all the IDisposable elements, rather than finally. Also; don't keep the connection while you show modal things like the message box, unless you need the connection afterwards. Frankly, a lot of benefit here could be made by cleanly separating the UI and data-access code, then there is not temptation to stick a message-box in the middle of a database query.
However! To be explicit, I believe this code is the victim of some other code that is hogging connections. Look at your other data access code for the cause of this.
Refactor your code to look something like this. Implement using blocks. The other answers here are very important, be sure to understand them.
bool res=false;
try
{
using(var connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString))
using(var cmd = conn.CreateCommand())
{
cmd.commandText = "Select IsAdmin from Users where UserName=#UserName And HashedAndSaltedPassword=#PwdHash";
cmd.Parameters.AddWithValue("#UserName", UserNameTextBox.Text.Trim());
cmd.Parameters.AddWithValue("#PwdHash", SaltAndHash(PasswordTextBox.Text));
connection.Open();
var result = cmd.ExecuteScalar();
if (result!=null)
{
res=bool.Parse(result);
this.DialogResult = DialogResult.OK;
}
}
}
catch (Exception ex)
{
if (progressForm != null){progressForm.Close();}
FMessageBox.ShowError(ex.Message);
}
if(res==false)
{
FMessageBox.ShowWarning("error");
UserNameTextBox.Focus();
}

Simultaneous connections MySql/C#

I have a WCF webservice that caters simultaneous requests from different clients. The service has to communicate with mysql Db on every request. The issue that i am facing is that a large number of requests come in at a same time (about 300-400) and while communicating with MySQL 'Unable to connect to any of the specified MySQL hosts' pops up.
What i've figured out till now is that Mysql is unable to manage so many simultaneous connections and fails to cater any more and starts throwing the error. What is the best way to get around this issue?
Following is the code snippet that is called every time a requests comes in:
try
{
MySqlCommand command = new MySqlCommand(query);
command.Connection = conn;
conn.Open();
long id = -1;
int _result = command.ExecuteNonQuery();
if (_result == 1)
{
//do something
}
conn.Close();
return id;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State != ConnectionState.Closed)
{
conn.Close();
}
}
How long does "//do something" take? If it's short, I don't see a whole lot you can do to
speed it up from the code. If it's long, consider closing the connection before doing whatever that is (presumably error handling).
(As a side note, you should try the using statement instead of the try/catch block to close the connection)
edit: Also, as SLaks said, "throw;" will do the same thing as "throw ex;" except it will preserve the stack trace, which is why you should not have the "ex;" on there, but this point is moot if you replace it with using.

Categories

Resources