C# doesn't catch execute non query exception - c#

I have this code that calls the stored procedure to 'insert' data to tables in SQL.
using (SqlConnection connection = new SqlConnection(Global_Variables.DBcon))
{
SqlCommand cmd = new SqlCommand("sp_WinApps_Import_ERData", connection);
cmd.CommandType = CommandType.StoredProcedure;
connection.Open();
try
{
cmd.ExecuteNonQuery();
Console.WriteLine("file imported!");
}
catch (SqlException ex)
{
Console.WriteLine("BATCH ID ALREADY EXISTS!" + ex.Message );
}
finally
{
connection.Close();
}
}
but the problem is, it doesn't catch the error in the 'try-catch method' i dont know why but my code is correct.
The Error says: "Violation of UNIQUE KEY constraint 'Cons_BatchID'. Cannot insert duplicate key in object 'dbo.tbl_WinApps_FileHeader'.
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
The statement has been terminated."

I solved it guys. Go to Debug > Exceptions and i just 'unchecked thrown checkbox' in Common Language Runtime Exceptions

Related

Postgres connection state stays active when an exception occurs

The state of the connection stays active in pool, when there is an exception while executing a query or stored procedure through c#.
The Npgsql version that I am using is 4.1.7.
Here is the code that I am trying to execute.
NpgsqlCommand cmd = null;
NpgsqlDataAdapter sda = null;
NpgsqlConnection conn = null;
try {
string sql = "a_test";
conn = new NpgsqlConnection("Server=localhost;Port=5432;Username=admin;Password=test;Database=majordb;SearchPath=dbs;CommandTimeout=300;MaxPoolSize=500;Connection Idle Lifetime=180;Connection Pruning Interval=5;");
cmd = new NpgsqlCommand(sql);
cmd.CommandType = CommandType.StoredProcedure;
sda = new NpgsqlDataAdapter(cmd);
cmd.Connection = conn;
sda.Fill(dataTable);
}
catch (Exception e) {
//log
}
finally {
if(null != sda)
{
try
{
sda.Dispose();
}
catch (Exception)
{
}
}
try
{
cmd.Connection.Close();
cmd.Connection.Dispose();
}
catch (Exception)
{
}
try
{
cmd.Dispose();
}
catch (Exception)
{
}
}
If the above code executes properly without any exception, the connection state in pool goes to idle, which is correct. But if an exception occurs while executing, like below:
"Npgsql.NpgsqlException (0x80004005): Exception while reading from stream --->
System.IO.IOException: Unable to read data from the transport connection: A connection attempt
failed because the connected party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond."
The connection state in pool shows as active for about 5 mins or so, even though the close/dispose methods are called in finally block. This means the close/dispose did not properly executed by Npgsql. If the program keeps the connection state in pool active for every connection ran within 5 mins, then there can be an issue with MaxPoolSize error.
I wanted to see the connection state to idle, even when there is an exception. How do I do this.
Please note: I am not looking for a solution to the exception that I listed above. I am looking for a solution where the connection state is changed to idle from active when there is an exception while executing the above code.
To know if the connection state is active or not I used the following query:
SELECT
pid,
usename,
application_name,
datname,
client_addr,
rank() over (partition by client_addr order by backend_start ASC) as rank,
state,
state_change,
current_timestamp,
query,
query_start,
backend_start,
FROM
pg_stat_activity
WHERE
pid <> pg_backend_pid( )
AND
application_name !~ '(?:psql)|(?:pgAdmin.+)'
AND
datname = current_database()
AND
usename = current_user
Any help is really appreciated.

C# SqlCommand Returning Input Parameters when Inserting multiple Records

I have an .exe project with 4 threads. Each thread makes a call to a WCF service hosted in a Windows Service and inserts a record (loop from 1 to 5,000 records). The test project will try to insert 20,000 records into the WCF service. The service behavior in the WCF service is per session.
I use a stored procedure to insert the records into SQL Server 2008R2 Express. The problem I'm having is with the SqlCommand. When only one thread is running, no error happens, but when two or more threads are running, the code throws an error, but not sure about the error type.
If you look at the code below, the error is raised when reading the result from the .ExecuteReader (it's a cast exception error). It does not return the errors that I have defined in the stored procedure (I'm guessing it never gets to the database), it returns an XML with all the parameters of the txn record, but it does not return only the current transaction, it also return record from transactions running on a different thread. If I execute the stored procedure directly in SQL Server Management Studio, it works fine, so I discarded any isolation level issue at the database side.
As you can see the method is not static, the SqlCommand is created and disposed on each call, so I'm really concerned about this. Any ideas?
private InsertInvoiceDataTable SaveTransaction(Transaction Trans, ClientInfo InfoCliente)
{
InsertInvoiceDataTable returnData = new InsertInvoiceDataTable();
try
{
using (SqlConnection con = new SqlConnection(ConnStr1)
{
using (SqlCommand cmd = new SqlCommand("InsertInvoice", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#TIPO", SqlDbType.Int).Value = Trans.InvoiceType;
cmd.Parameters.Add("#CAJERO", SqlDbType.VarChar).Value = Trans.Cashier;
cmd.Parameters.Add("#TERMID", SqlDbType.Int).Value = Trans.Term;
cmd.Parameters.Add("#DOB", SqlDbType.DateTime).Value = Trans.DOB;
cmd.Parameters.Add("#CLIID", SqlDbType.VarChar).Value = InfoCliente.ClientId;
cmd.Parameters.Add("#VENTANETA", SqlDbType.Decimal).Value = Convert.ToDecimal(Trans.SubTotal);
cmd.Parameters.Add("#IMPUESTO", SqlDbType.Decimal).Value = Convert.ToDecimal(Trans.TaxTotal);
cmd.Parameters.Add("#VENTATOTAL", SqlDbType.Decimal).Value = Convert.ToDecimal(Trans.Total);
con.Open();
using (SqlDataReader results = cmd.ExecuteReader())
{
while (results.Read())
{
InsertInvoiceRow row = returnData.NewInsertInvoiceRow();
try
{
row.TIPO_log = results["Type_log"].ToString();
row.VALOR_LOG = results["Value_log"].ToString();
}
catch (Exception ex)
{
returnData.AddInsertInvoiceRow("ERROR", ex.Message);
break;
}
returnData.AddInsertInvoiceRow(row);
}
}
con.Close();
cmd.Dispose();
}
}
}
catch (Exception ex)
{
Log.Error(ex);
returnData.AddInsertInvoiceRow("ERROR", ex.Message);
}
return returnData;
}
You are performing a DML operation, in your case INSERT (from your posted code new SqlCommand("InsertInvoice", con)) then why ExecuteReader() it rather should be cmd.ExecuteNonQuery()

How can I determine the precise exception when a connection to SQL Server fails (C#)?

I have a (Windows Forms) app that will be installed on various users' desktops; it will allow them to generate reports based on custom code that connects to a SQL Server Database and reads records from certain tables.
The Connection String is:
Data Source=PLATYPUS;Initial Catalog=Duckbills;Persist Security Info=True;User ID=lilabner;Password=d0GpAtCh42;Connect Timeout=120
I understand this to mean that if all the following is true:
The user's machine has the SQL Server client software installed
The SQL Server client has been configured to access the PLATYPUS database
The table "Duckbills" exists in that database
The username and password are what is expected
...then the connection will be successful.
In the event any of the above equate to false, I want to show the user a "user-friendly" message informing them, in plain English, what the problem is and what to do about it. How can I test for these various problems so that the most appropriate message is shown the user in the event of connection failure.
Here is the pertinent existing code:
DataSet dsUsage = new DataSet();
SqlConnection conn =
new SqlConnection("SERVER=PLATYPUS;DATABASE=Duckbills;UID=lilabner;PWD=d0GpAtCh42;Connection Timeout=0");
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "Exec sp_ViewPlatypi";
da.SelectCommand = cmd;
conn.Open();
da.Fill(dsUsage);
conn.Close();
DataTable dtUsage = dsUsage.Tables[0];
if (dtUsage.Rows.Count > 0)
{
foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows)
{
. . .
catch (Exception ex)
{
String exDetail = String.Format(PlatypusConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
As you can see, I have a "catch all" (no pun intended) Catch block. I want something like:
catch (SQLServerException sex)
{
MessageBox.Show("SQL Server not available - go tell the DBA");
}
catch (NoTableException ntex)
{
MessageBox.Show("Go tell the DBA there's no such table");
}
catch (BadPwdException sex)
{
MessageBox.Show("Your username and/or password are bad - go tell it to the Marines");
}
catch (Exception ex)
{
String exDetail = String.Format(PlatypusConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
...but I don't know, first if all, if it's even possible to get that granular with connection exception messages, and secondly - if it is - just what the corresponding Exception types are.
Strip your code back to handle Exception (catch (Exception ex)). Then, put a break point in your catch block. Attach the debugger to your code and when it hits the catch block, drag the ex variable in to your watch window. There, you will see all the details of the exception and you can determine what you need to be able to better handle the various exceptions that come up.
Based on MethodMan's suggestion and TheShaman's link, I adapted that code to this:
catch (SqlException sex)
{
for (int i = 0; i < sex.Errors.Count; i++)
{
String sexDetail = String.Format("SQL Exception #{0}{1}Source: {2}{1}Number: {3}{1}State: {4}{1}Class: {5}{1}Server: {6}{1}Message: {7}{1}Procedure: {8}{1}LineNumber: {9}",
i+1, // Users would get the fantods if they saw #0
Environment.NewLine,
sex.Errors[i].Source,
sex.Errors[i].Number,
sex.Errors[i].State,
sex.Errors[i].Class,
sex.Errors[i].Server,
sex.Errors[i].Message,
sex.Errors[i].Procedure,
sex.Errors[i].LineNumber);
MessageBox.Show(sexDetail);
}
}
catch (Exception ex)
{
String exDetail = String.Format(UsageRptConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
And for an example of what this produces:

SQLTransaction has completed error

I got following error once in my application.
This SQLTransaction has completed; it is no longer usable
Stack Trace is attached below – It says about Zombie Check and Rollback.
What is the mistake in the code?
Note: This error came only once.
UPDATE
From MSDN - SqlTransaction.Rollback Method
A Rollback generates an InvalidOperationException if the connection is terminated or if the transaction has already been rolled back on the server.
From Zombie check on Transaction - Error
One of the most frequent reasons I have seen this error showing up in various applications is, sharing SqlConnection across our application.
CODE
public int SaveUserLogOnInfo(int empID)
{
int? sessionID = null;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
transaction.Dispose();
transaction = null;
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
}
}
return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture);
}
Stack Trace
REFERENCE:
What is zombie transaction?
Zombie check on Transaction - Error
SqlTransaction has completed
http://forums.asp.net/t/1579684.aspx/1
"This SqlTransaction has completed; it is no longer usable."... configuration error?
dotnet.sys-con.com - SqlClient Connection Pooling Exposed
Thread abort leaves zombie transactions and broken SqlConnection
You should leave some of the work to compiler, to wrap that in a try/catch/finally for you.
Also, you should expect that Rollback can occasionally throw an exception, if a problem occurs in Commit stage, or if a connection to server breaks. For that reason you should wrap it in a try/catch.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
This is copied exactly from MSDN documentation page for Rollback method.
I see that you're worried that you have a zombie transaction. In case you pasted, it doesn't sound like you have a problem. You're transaction has been completed, and you should no longer have anything to do with it. Remove references to it if you hold them, and forget about it.
From MSDN - SqlTransaction.Rollback Method
A Rollback generates an InvalidOperationException if the connection is terminated or if the transaction has already been rolled back on the server.
Rethrow a new exception to tell user that data may not have been saved, and ask her to refresh and review
Note: This error came only once.
then it is very hard to say much; it could be simply that the // Other Code etc simply took to long, and the entire thing got killed. Maybe your connection died, or an admin deliberately killed it because you were blocking.
What is the mistake in the code?
over-complicating it; it can be much simpler:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using(var transaction = connection.BeginTransaction())
{
try
{
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
much less code to get wrong.
I use code below can reproduce this error, I use 1000 tasks to execute Sql, after about 300 tasks Successfully Completed, lots of exception about timeout error start to occur on ExecuteNonQuery(),
then next error This SqlTransaction has completed will occur on transaction.RollBack(); and its call stack also contains ZombieCheck().
(If single program with 1000 tasks pressure not enough, you can execute multiple compiled exe file at the same time, or even use multi computers execute to one DataBase.)
So I guess one of the reason cause this error can be something wrong in Connection, then cause the transaction error happens as well.
Task[] tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
int j = i;
tasks[i] = new Task(() =>
ExecuteSqlTransaction("YourConnectionString", j)
);
}
foreach (Task task in tasks)
{
task.Start();
}
/////////////
public void ExecuteSqlTransaction(string connectionString, int exeSqlCou)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction();
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"select * from Employee";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
Console.WriteLine("Execute Sql to database."
+ exeSqlCou);
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
Besides I find if I commit twice sequentailly will invoke this exception as well.
transaction.Commit();
transaction.Commit();
Or if Connection Closed before commit also invoke this error.
connection.Close();
transaction.Commit();
Update:
I find it strange that I create another new table and insert 500 thousand data to it,
then use 100000 tasks with select * from newtable sql, running 5 programs at the same time, this time the Timeout Error occur, but when transaction.Rollback() it didn't invoke the SQLTransaction has completed error.
but if the Timeout Error occur, jump into the catch block, and in the catch block do transaction.Commit() again, the SQLTransaction has completed error will happen.
I have experienced this error once and i was stuck and unable to know what is going wrong. Actually i was deleting a record and in the Stored procedure i was not deleting its child and specially the delete statement in Stored Procedure was inside the Transaction boundary. I removed that transaction code from stored procedure and got rid of getting this Error of “This SqlTransaction has completed; it is no longer usable.”
This message is simply because that you wrote code that throws an exception after the transaction has been already committed successfully.Please try to check the code you wrote after the Commit method or you can handle it by using Try..Catch and finally Blocks :) .

How to catch SQLServer timeout exceptions

I need to specifically catch SQL server timeout exceptions so that they can be handled differently. I know I could catch the SqlException and then check if the message string Contains "Timeout" but was wondering if there is a better way to do it?
try
{
//some code
}
catch (SqlException ex)
{
if (ex.Message.Contains("Timeout"))
{
//handle timeout
}
else
{
throw;
}
}
To check for a timeout, I believe you check the value of ex.Number. If it is -2, then you have a timeout situation.
-2 is the error code for timeout, returned from DBNETLIB, the MDAC driver for SQL Server. This can be seen by downloading Reflector, and looking under System.Data.SqlClient.TdsEnums for TIMEOUT_EXPIRED.
Your code would read:
if (ex.Number == -2)
{
//handle timeout
}
Code to demonstrate failure:
try
{
SqlConnection sql = new SqlConnection(#"Network Library=DBMSSOCN;Data Source=YourServer,1433;Initial Catalog=YourDB;Integrated Security=SSPI;");
sql.Open();
SqlCommand cmd = sql.CreateCommand();
cmd.CommandText = "DECLARE #i int WHILE EXISTS (SELECT 1 from sysobjects) BEGIN SELECT #i = 1 END";
cmd.ExecuteNonQuery(); // This line will timeout.
cmd.Dispose();
sql.Close();
}
catch (SqlException ex)
{
if (ex.Number == -2) {
Console.WriteLine ("Timeout occurred");
}
}
here: http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.adonet/2006-10/msg00064.html
You can read also that Thomas Weingartner wrote:
Timeout: SqlException.Number == -2 (This is an ADO.NET error code)
General Network Error: SqlException.Number == 11
Deadlock: SqlException.Number == 1205 (This is an SQL Server error code)
...
We handle the "General Network Error" as a timeout exception too. It only occurs under rare circumstances e.g. when your update/insert/delete query will raise a long running trigger.
Updated for c# 6:
try
{
// some code
}
catch (SqlException ex) when (ex.Number == -2) // -2 is a sql timeout
{
// handle timeout
}
Very simple and nice to look at!!
Whats the value for the SqlException.ErrorCode property? Can you work with that?
When having timeouts, it may be worth checking the code for -2146232060.
I would set this up as a static const in your data code.
I am not sure but when we have execute time out or command time out
The client sends an "ABORT" to SQL Server then simply abandons the query processing. No transaction is rolled back, no locks are released. to solve this problem I Remove transaction in Stored-procedure and use SQL Transaction in my .Net Code To manage sqlException
When a client sends ABORT, no transactions are rolled back. To avoid this behavior we have to use SET_XACT_ABORT ON
https://learn.microsoft.com/en-us/sql/t-sql/statements/set-xact-abort-transact-sql?view=sql-server-ver15

Categories