SQL Insert Query not executing without throwing any exception in c# - c#

I wrote an insert function for a discussion forum website to insert new discussion threads in database. The function is as follows:
public int createDiscuss(Discussion dis)
{
query = "insert into [MyForums].[dbo].[Discussions](desid, text, date, time, replyto, uid, isPrivate) values(#id, #text, #date, #time, #replyto, #uid, #pvp)";
string did=getDesID();
if (did == null)
return -1;
try
{
com = new SqlCommand(query, con);
com.Parameters.AddWithValue("#id", did);
com.Parameters.AddWithValue("#text", dis.gettext());
com.Parameters.AddWithValue("#date", SqlDateTime.Parse(DateTime.Now.ToString()));
com.Parameters.AddWithValue("#time", SqlDateTime.Parse(DateTime.Now.ToString()));
com.Parameters.AddWithValue("#replyto", dis.getreplyto());
com.Parameters.AddWithValue("#uid", dis.getuid());
if (dis.IsPrivate() == false)
{ com.Parameters.AddWithValue("#pvp", 1); }
else
{ com.Parameters.AddWithValue("#pvp", 2); }
con.Open();
int r=com.ExecuteNonQuery();
if (r <= 0)
{
return -1;
}
con.Close();
}
catch (Exception)
{
return -1;
}
return 0;
}
This function if encounters an error or exception than it return -1 and which is checked by the calling function and then the calling function shows error. The problem is that this insert function is not executing query. When I checked that if the values are properly passing or not to the AddWithValue function as an argument, I found that every value is passed as it was given on the asp.net page. But when control comes to com.ExecuteNonQuery() function. It is returning -1 that is error. Can anyone tell me whats wrong with my code? or how can I check why com.ExecuteNonQuery() not returning any effected row??
This exception showing
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code

You should close your connection in a finally block. Any exception you encounter before con.Close(); will result in your connection being left open. That could be the error here (depending on the scope of con)
You should not swallow the exception, but log it. Then you can examine the errors properly. If you don't have logging, get logging. But in the meantime, look at the exception you have caught using the debugger.
You should also catch more specific exceptions, so that you can tell the difference between a connectivity error and a chronic bug in the application. Check which exceptions are likely to be thrown by the methods you are calling. For example, con.Open() can throw these:
SqlException
InvalidOperationException
So catch those first, and catch Exception last.
Depending on the type of exception you can return a different error code and/or log at a different level of severity.
Also, figure out a way (using profiling or just copy+paste) to run that query against the database and see what happens. For example, are you sure this part is right:
com.Parameters.AddWithValue("#date",
SqlDateTime.Parse(DateTime.Now.ToString()));
com.Parameters.AddWithValue("#time",
SqlDateTime.Parse(DateTime.Now.ToString()));
#date and #time are identical. Are the database values identical too and are the columns both expecting strings?

That being said, SQL Profiler is your friend here. Grab the generated sql from profiler and run it in SQL mgmt studio. I am 99% confident the answer will be obvious. If not, then please update your answer with the generated sql from profiler, and we'll take it from there.
If you need some guidance on SQL Profiler, a simple Google search brings up many options: SQL Profiler Search

You need to do some basic debugging. Setup your code like:
catch(Exception ex)
{
return -1;
}
Set a break point on return, and see what the Exception is.

you are probably not reaching the int r=com.ExecuteNonQuery(); code. Could be an error on the con.Open(); method.
Could you throw a new exception inside your catch and show us the actual error?

A challenge with your current code is that "-1" is returned in several different scenarios:
Exception occurs
result of getDesID is null
INSERT statement fails to insert a row
One simple way to check this would be to return a different number (say -2 or -3) from each point of failure. That way you can determine where the error is being raised without changing your code much or attaching a debugger.
It appears to me that the issue is not likely your SQL INSERT statement - if the statement itself was invalid or violated a database constraint, SQL Server would raise an exception back to you which would be caught by your Exception handler.

Related

Should we put try catch with function if we just want to log the exception?

In asp.net application, all the exception that occurs and are not inside try catch can be handled by application_error.
If we just need to log the exception along with its stack trace, and we need not make any other decision/logic inside catch, why should we put try catch at application/bl or dal layer functions? Is there any reason to put try/catch with every database call function?
For example we have hundreds of function in DAL layer that executes following code:
try
{
//open db connection, execute stored procedure
}
catch
{
//log error
}
In case we get any exception from stored procedure OR in opening database connection, we get an exception but we are not doing anything except for logging these errors. We don't have very critical data-storage/retrieval requirement. We are logging error just to be alerted and fix it later. Is this correct to put catch in every such function?
Using try and catch is not for logging purposes only, especially when dealing with database connections.
An exception means that something wasn't completed. If something wasn't completed, your business process failed. If your business process failed, you need to know about it and handle it within the scope of that code, not application_error. Each error should be handled within the scope it was generated from. application_error should be your last fallback, and theoretically should never be reached.
Sure, you can use it for logging, but also for closing your DB connection (which was probably opened before the exception occurred and be left forever open), informing your users that an exception occured, and for data recovery, alternating your process to deal with the exception or preparing it for a retry.
So, taking your posted template, good code handling should look like this:
try
{
//open db connection, execute stored procedure
}
catch
{
// Inform the user
// Alternate your process or preparing for retry
// log error
}
finally
{
// Close the DB connection
}
One should use try/catch blocks only in places where you can meaningfully handle an exception. However, "meaningful handling " includes providing good error messages.
If your catch block simply logs the exception with no additional context, then such block could be replaced with a top-level handler (like application_error) that does the same thing.
If, however, you log additional information available only at the point of invocation, then having a catch block is entirely justified: it enhances the experience by providing better diagnostics, which is a perfectly legitimate goal.

Get Trigger's name or error message in DbUpdateException

I have several triggers in the database and based on some conditions they might throw an error and rollback transaction.
The problem is that in the catch block I'll receive a DbUpdateException that doesn't contain any information about the cause of the error, and inner exceptions don't have any meaningful error message neither.
How can I get the error message or trigger's name, when I'm using Entity Framework? I need to do that to be able to show friendly messages to the user.
The second inner exception is a SqlException, yet casting it to a SqlException doesn't help since the Procedure is an empty string.
(e?.InnerException?.InnerException as System.Data.SqlClient.SqlException).Procedure
To get the trigger name, you'll need to include that in the error message. Below is a boilerplate code example.
CREATE TRIGGER TR_YourTable ON dbo.YourTable
FOR INSERT, UPDATE, DELETE AS
BEGIN TRY
--do something;
END TRY
BEGIN CATCH
DECLARE #ErrorMessage nvarchar(2000) =
'Error occurred in trigger ' + OBJECT_NAME(##PROCID) + ':' + ERROR_MESSAGE();
RAISERROR(#ErrorMessage,16,1);
END CATCH;
GO
This reply assumes you are using MSSQL Server...if not ignore...
IN your SQL code change RAISERROR to:
THROW 50000, <#YourErrormsg>, 16 ;
Notes on SQL code:
if you are not useing semicolons after your statements, THROWS needs one in front of it, else it generates error (server won't let you update trigger).
If you want to rollback entire trans (say code is in trigger) before THROW do: SET XACT_ABORT ON. Unlike RAISERROR, THROWS uses XACT_ABORT to detirmine to rollback or not (thus can be used for FYI messages as well if SET XACT_ABORT OFF).
Error# needs to be => 50000. Use a specific number if you are using numbers have additional meaning (you could have C# enum on client side in a switch, I just set to 50001 for all business errors in trigger as I just needed message).
In your C# code use try catch with a catch of:
catch (Microsoft.Data.SqlClient.SqlException ex)
At first I had just (SqlException ex), but that resolved to: System.Data.SqlClient.SqlException, which will NOT have your message.
Use full: Microsoft.Data.SqlClient.SqlException for your catch.
ex.Messsage will have your custom set message in your sql code.
ex.Prodecure will have the name of the database object that throws it (it my case it was a trigger as well, so that's where to look)
This took me a while to figure out, especially the Microsoft.Data.SqlClient.SqlException vs
System.Data.SqlClient.SqlException

Exception Handling error when saving to database

Iam a newbie who needs help. When saving to a database, i get the following error:
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in (name of my application)
Please help me with steps to solve this one. Thank you in advance.
First chances exceptions will be shown if you have your Visual Studio settings set so that every CLR exceptions gets reported. This will include exceptions you actually handle.
In Visual Studio's menu, go to Debug > Exceptions and uncheck the Thrown option for Common Language Runtime Exceptions.
Of course that won't make the actual exception go away but you'll be allowed to handle it as you want:
try
{
// do your query
// commit current transaction if possible/necessary
}
catch (SqlCeException ex)
{
// handle exception here and rollback current transaction if possible/necessary
}
finally
{
// ensure proper disposal of any commands and connections you have
}
It goes without saying that you must ensure your query is properly written and that the server objects it tries to work with exists. You generally won't want to handle cases where a comma is missing or a field is not found, for instance. Exception handling must be for exceptional situations your code cannot control, like a faulted connection, a server malfunction, etc.
First of all you might want to check whehter your SQL query is syntactically correct.
Secondly you might want to read about how to handle exceptions in MSDN http://msdn.microsoft.com/en-us/library/0yd65esw.aspx with try-catch statement.
A small example looks like this.
try
{
// ... code which throws exception
}
catch (SqlCeException e)
{
// ... exception handling, e.g. logging, rolling back data,
// telling the user something went wrong, you name it
}
Last but not least you might want to debug your application step by step to see what is causing the error and what the actual SQL Query is throwing the exception.

SqlTransaction causing application crash on error?

Here's some background: Periodically our site will crash to the point of having to restart IIS; this almost always happens within an hour of patching a DLL (we use a Web Site project, not a Web Application project, so each ASPX page is a separate DLL).
In doing some research I have found that our homebrew DAL can, while debugging, cause the built-in webserver with Visual Studio to actually stop working and be shut down if it encounters a SQL error in a stored procedure (I mean it will not only throw an exception that is displayed in the browser, it will actually say that the web server has experienced an error and needs to close!)
In digging further the error seems to be related to the use of transactions for everything (including Select statements) in the DAL. What seems to happen is this:
Tries to execute stored procedure, stored procedure fails due to missing/invalid column or other error.
Application code catches the error and rethrows it (bad, yes, but I didn't write this).
Transaction tries to commit despite the exception, gets a NullReferenceException on the transaction.Commit() line (seems to be on the Connection property because there is a transaction object). Also this NullRef seems like it cannot be caught (I tried a demo that force crashed with an invalid Sproc and the NullRef was never caught even though outputting the error gave its type as System.NullReferenceException)
Transaction throws error that say something like "The transaction has completed and is no longer usable".
??? but the VS web server crashes. Debugging this part seems to hang on the above exception, never leaving the method.
Now, I don't know if this is what causes IIS to crash, but it seems quite suspicious and it's a glaring error in any event.
Having not dealt with transactions before and having only the basic idea of them, my first question is why the transaction is still trying to commit after an exception is being thrown? My second question is how to fix the failing commit and presumably infinite looping of exceptions until the server dies. Wouldn't it make sense to add something like this (the method takes a SqlTransaction parameter named transaction):
catch (SqlException se)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
Would that small change fix the constant exception loop that I think is crashing IIS? The DAL itself is extremely brittle and is used concretely in hundreds of files so I can't rewrite it from scratch correctly.
EDIT The entire code block is this (again, legacy code - uses the old microsoft data access block helper):
public static DataSet ExecuteDatasetStoredProc(SqlConnection conn, String storedProcName, SqlTransaction transaction, params SqlParameter[] storedProcParms)
{
try
{
// Execute the stored proc
if (transaction != null)
{
return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
else
{
return SqlHelper.ExecuteDataset(conn, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
}
catch (SqlException se)
{
throw new ApplicationException("Error calling " + storedProcName + ". " + se.Message, se);
}
}
However, if the catch block executes the transaction still tries to commit and this seems to be causing the hangups.
also Change your if you wrap your Transactional code in a try catch
Try
{
// your code that you assign and execute the SQl
}
catch (SQLException sqlex)
{
try
{
//try to do the rollback here.. don't always assume the commit or rollback will work
}
catch (Your SQL Exception ex)
{
}
}

How can I handle an exception in DataSet.Designer.cs?

I'm using Visual Studio 2008 along with C# to access a MySql database. To this point I have relied on Visual Studio to create the code for the DataSet, and that seems to have given me a problem. If the database is inaccessible (i.e. not running) it gives a "MySqlException was unhandled", "unable to connect to any of the specified MySQL hosts".
My question is what is the best way to handle this exception?
I would like to be able to handle it without tampering with the designer.cs file, but if that is not possible then any way of solving this will do.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter")]
[global::System.ComponentModel.DataObjectMethodAttribute(global::System.ComponentModel.DataObjectMethodType.Fill, true)]
public virtual int Fill(customerDataSet.addressesDataTable dataTable) {
this.Adapter.SelectCommand = this.CommandCollection[0];
if ((this.ClearBeforeFill == true)) {
dataTable.Clear();
}
// Exception occurs on the line below.
int returnValue = this.Adapter.Fill(dataTable);
return returnValue;
}
When handling exceptions, you should catch the exception at the earliest moment you have something you want to do in response to the exception. A DataSet is a poor place to handle the event of your database being inaccessible; how will the rest of your application be notified that this error has occured?
In your case, how do you wish to handle this MySqlException being thrown? In most cases, an inaccessible database is going to be a difficult error to recover from. You may wish to let the exception bubble up through your current process and simply display an error message, or you might want to re-attempt the process, or you may wish to switch to another database.
It sounds to me that you might want to do some general reading around the purpose of exceptions and why the "throw" mechanism exists. They're not simply there to annoy you into writing try-catch blocks!

Categories

Resources