Stored procedure calling working randomly [duplicate] - c#

This question already has answers here:
C# & SQL Server : inserting/update only truly executes when debugging
(2 answers)
Closed 7 years ago.
I'm calling two stored procedures from a Windows service developed in C#. It should write two records in a determined table on the DB.
The stored procedures had been tested and executed from SQL Server Management Studio and they ALWAYS work well, so my problem is with the calling to them.
The weird part is that it works randomly. Some times it works just fine, but most of them time, the service doesn't execute the procedures. I had debugged it and the result of BeginExecuteNonQuery() is always "Ran To Completion", so it says that runs ok.
I'm including the code of the methods which make the calling. I don't include the stored procedures code because they are huge and as I said they always work fine when you execute it in from Management Studio with passing NULL as parameters. Of course, I don't have any connection or stored procedure naming problem.
public void Process()
{
if (!_initialized)
Initialize();
Stopped = false;
try
{
// Calling Sales sp
DoOutboundProcedure("procedure1", null, null, null);
// Calling Returns sp
DoOutboundProcedure("procedure2", null, null, null);
}
catch (Exception ex)
{
_logger.Error(ex.Message);
}
}
public void DoOutboundProcedure(string procedureName, object i_TraceOn, object i_Validate, DateTime? i_NextDateLastModified)
{
using (SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(procedureName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#i_TraceOn", SqlDbType.TinyInt).Value = i_TraceOn;
cmd.Parameters.Add("#i_Validate", SqlDbType.Bit).Value = i_Validate;
cmd.Parameters.Add("#i_NextDateLastModified", SqlDbType.DateTime).Value = i_NextDateLastModified;
con.Open();
_logger.Trace("Calling store procedure \"{0}\".", procedureName);
var result = cmd.BeginExecuteNonQuery();
_logger.Trace("Stored procedure calling finished.");
con.Close();
}
}
}

Since you're trying to do this operation asynchronously with BeginExecuteNonQuery() you have to finish the operation with EndExecuteNonQuery()
Per MSDN:
When you call BeginExecuteNonQuery to execute a Transact-SQL statement, you must call EndExecuteNonQuery in order to complete the operation. If the process of executing the command has not yet finished, this method blocks until the operation is complete. Users can verify that the command has completed its operation by using the IAsyncResult instance returned by the BeginExecuteNonQuery method. If a callback procedure was specified in the call to BeginExecuteNonQuery, this method must be called.
An example of how to use this, as taken from MSDN:
SqlCommand command = new SqlCommand(commandText, connection);
connection.Open();
IAsyncResult result = command.BeginExecuteNonQuery();
while (!result.IsCompleted)
{
Console.WriteLine("Waiting ({0})", count++);
// Wait for 1/10 second, so the counter
// does not consume all available resources
// on the main thread.
System.Threading.Thread.Sleep(100);
}
Console.WriteLine("Command complete. Affected {0} rows.",
command.EndExecuteNonQuery(result));

Related

Why does commandTimeout raise SqlError in IDbConnection.Execute?

I have an IDbConnection to a SQL server and two stored procedures I would like to start from a console app using the Execute method on the open connection. When I run the first one, there are no problems, but the second one takes more than 30 seconds to execute, so a Timeout is raised.
According to the Internet, waiting for a command to execute is changed with the commandTimeout parameter, but after adding the commandTimeout: 0, commandTimeout: 99999, or commandTimeout: null, both Executes raise a SQL error: String or binary data would be truncated.
These errors don't happen if I run the procedure in MS SQL Server Management Studio.
What should I do to wait for a longer time for the procedure to execute and why does adding a commandTimeout give and error about truncating?
I tried searching for a solution, but I'm not well versed in C# yet and didn't find anything useful.
Edit:
Some of you asked for tables or procedures, which I cannot give due to privacy reasons. However they are working correctly when executed in a query in the MS SQL Server Management Studio.
Here's the code in question:
public class MlCePredictedSqlSrvRepository : IMlCePredictedSqlSrvRepository
{
private IDbConnection _dbConnection;
public MlCePredictedSqlSrvRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public bool ExecuteStoredProcedure()
{
try
{
string sql = #"[dbo].[StoredProcedure]";
_dbConnection.Open();
var procedure = _dbConnection.Execute(sql, commandType: CommandType.StoredProcedure, commandTimeout: 0);
_dbConnection.Close();
Console.WriteLine("Stored Procedure successfully executed.");
return true;
}
catch (Exception ex)
{
Console.WriteLine("\tException in the Stored Procedure: " + ex.GetType().Name + "; " + ex.GetBaseException().Message);
_dbConnection.Close();
return false;
}
}
}
It's called directly in the Program. The only change from working (albeit with a Timeout) to not working is the last parameter in Execute

EF Core ExecuteReader or ExecuteScalar - Stored Procedure Incorrect parameter but no exception

I'm using .Net EF Core 3.1.5, I need to call an existing SQL Server stored procedure with parameters.
The procedure is executing fine and the parameter I pass in are working.
I'm having an issue whereby no warning or errors are being caught from SQL Server. My stored procedure is 'GetProcessEvents' which takes parameter #runId. If I change #runId to be #xxxxxId in my C# the stored procedure will not run but no error will be returned to my C#.
I've tried return Convert.ToInt32(cmd.ExecuteScalar()); and as in the code below 'ExecuteReader' but neither work. Even if I put a 'select 100/0' in the stored procedure no exception is returned - If I run the procedure directly in SQL Server Management Studio I get "Msg 8134, Level 16, State 1, Line 1. Divide by zero error encountered." which I would expect as an exception in C#.
try
{
if (sqlConn == null)
return 0;
DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "GetProcessEvents";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#runId", runId));
if (cmd.Connection.State != ConnectionState.Open)
cmd.Connection.Open();
var reader = cmd.ExecuteReader();
if (reader.HasRows) // I've tried with and without this if
{
while (reader.Read())
return reader.GetInt32(0);
}
return runId;
}
catch (SqlException sqle)
{
throw sqle; // No exception ever caught
}
catch (Exception e)
{
throw e;
}
Do I need to try one of the other solutions in This StackOverflow - Although I tried FromSql and Visual Studio indicates it's obsolete.
Please help. Many thanks!
Also, In case this adds anything, I'm using SignalR successfully to retrieve SQL Server warning (< less than severity 10 - so not error) events (SQL: RAISERROR ( '1' ,0, 10) WITH NOWAIT) raised from the stored procedure which fires back progress events as the possibly long running procedure is executing. This is working fine and the events are being received by C# from SQL Server.
Please Note: I have tried the above issue with and without wiring up the code below.
sqlConn.FireInfoMessageEventOnUserErrors = true;
// Number of times the stored procedure(s) will return notifications to the Client
if (percentageNotifications == null)
percentageNotifications = 10;
// Wire up delegate to SQL Server connection
sqlConn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
{
// Fire notification to SignalR Hub and anwards to client on RAISERROR (severity <10: just a message) from Sql Server
NotificationsComplete++;
_contextHub.Clients.All.SendAsync("UpdateProgressBar", taskId, ((100 / percentageNotifications) * NotificationsComplete).ToString());
};

Can Execution Time be set in Entity Framework?

I have an application leveraging Entity Framework 6. For queries that are relatively fast (e.g. taking less than a minute to execute) it is working fine.
But I have a stored procedure that queries a table which doesn't have appropriate indices and so the time taken to execute the query has been clocked to take anywhere between 55 and 63 seconds. Obviously, indexing the table would bring that time down but unfortunately I don't have the luxury of controlling the situation and have to deal the hand I was dealt.
What I am seeing is when EF6 is used to call the stored procedure it continues through the code in less than 3 seconds total time and returns a result of 0 records; when I know there are 6 records the SPROC will return when executed directly in the database.
There are no errors whatsoever, so the code is executing fine.
Performing a test; I constructed some code using the SqlClient library and made the same call and it returned 6 records. Also noted that unlike the EF6 execution, that it actually took a few more seconds as if it were actually waiting to receive a response.
Setting the CommandTimeout on the context doesn't appear to make any difference either and I suspect possibly because it isn't timing out but rather not waiting for the result before it continues through the code?
I don't recall seeing this behavior in prior versions but then again maybe the time required to execute my prior queries were within the expected range of EF???
Is there a way to set the actual time that EF will wait for a response before continuing through the code? Or is there a way that I can enforce an asynchronous operation since it seems to be a default synchronous task by default?? Or is there a potential flaw in the code?
Sample of Code exhibiting (synchronous) execution: No errors but no records returned
public static List<Orphan> GetOrphanItems()
{
try
{
using (var ctx = new DBEntities(_defaultConnection))
{
var orphanage = from orp in ctx.GetQueueOrphans(null)
select orp;
var orphans = orphanage.Select(o => new Orphan
{
ServiceQueueId = o.ServiceQueueID,
QueueStatus = o.QueueStatus,
OrphanCode = o.OrphanCode,
Status = o.Status,
EmailAddress = o.EmailAddress,
TemplateId = o.TemplateId
}).ToList();
return orphans;
}
}
catch(Exception exc)
{
// Handle the error
}
}
Sample Code using SqlClient Library (asynchronous) takes slightly longer to execute but returns 6 records
public static List<Orphan> GetOrphanItems()
{
long ServiceQueueId = 0;
bool QueueStatus;
var OrphanCode = String.Empty;
DateTime Status;
var EmailAddress = String.Empty;
int TemplateId = 0;
var orphans = new List<Orphan> ();
SqlConnection conn = new SqlConnection(_defaultConnection);
try
{
var cmdText = "EXEC dbo.GetQueueOrphans";
SqlCommand cmd = new SqlCommand(cmdText, conn);
conn.Open();
SqlDataReader reader;
reader = cmd.ExecuteReader();
while(reader.Read())
{
long.TryParse(reader["ServiceQueueId"].ToString(), out ServiceQueueId);
bool.TryParse(reader["QueueStatus"].ToString(), out QueueStatus);
OrphanCode = reader["OrphanCode"].ToString();
DateTime.TryParse(reader["Status"].ToString(), out Status);
EmailAddress = reader["EmailAddress"].ToString();
int.TryParse(reader["TemplateId"].ToString(), out TemplateId);
orphans.Add(new Orphan { ServiceQueueId = ServiceQueueId, QueueStatus=QueueStatus, OrphanCode=OrphanCode,
EmailAddress=EmailAddress, TemplateId=TemplateId});
}
conn.Close();
catch(Exception exc)
{
// Handle the error
}
finally
{
conn.Close();
}
}
Check the type of executing method.
private async void MyMethod()
{
db.executeProdecudeAsync();
}
Forgetting to await task in async void method can cause described behavior without any InteliSense warning.
Fix:
private async Task MyMethod()
{
await db.executeProdecudeAsync();
}
Or just use db.executeProdecudeAsync().Wait() if you want to run in synchronous mode.

How to put a timeout on a method C#

Hi all I just had a quick question for you all. For whatever reason, a piece of code periodically does not return and I am not 100% sure yet. To combat this for now, I want to know, using the Close() method below, is there a way to put a timeout on it? So, if it does not finish within 1 minute or so, it just moves on?
Any advice would be appreciated. Thank you,
If it makes any difference, the original writer who wrote this noted that he believed it hangs on the close() and noted "Maybe Too fast?" (The connection is an oledb connection to Netezza, the whole applications is heavily multi-threaded).
Anyways, for now, I just want to be able to get the application to at least finish instead of hanging on that exception catch.
below is the Close(); which I believe is not returning.
catch(Exception){
Close(); //-- if we have an error, close everything down and then return the error
throw;}
public void Close() {
if (null != Command) {
Command.Cancel();
Command.Dispose();
Command = null;
}
if (null != Connection) {
if (Connection.State != System.Data.ConnectionState.Closed)
Connection.Close();
Connection.Dispose();
Connection = null;
}
}
Rather than timeout on a Method do you really mean timeout on a Command?
Based on that Close() you are sharing Command and Connection.
That is not a good design for a heavily multi-threaded application.
That is not a good design from even a lightly multi-threaded application.
DbCommand has a timeout property
Using statement will perform cleanup (including close)
string connectionString = "";
// Wait for 5 second delay in the command
string queryString = "waitfor delay '00:00:05'";
using (OleDbConnection connection = new OleDbConnection(connectionString )) {
connection.Open();
SqlCommand command = new connection.CreateCommand();
// Setting command timeout to 1 second
command.CommandText = queryString;
command.CommandTimeout = 1;
try {
command.ExecuteNonQuery();
}
catch (DbException e) {
Console.WriteLine("Got expected DbException due to command timeout ");
Console.WriteLine(e);
}
}
Assuming you're using .NET 4.0 and above, you can use the TPL to do so using the System.Threading.Tasks.Task object. You create a Task to run a method asynchronously, then Wait on that task for your timeout duration, and if it expires - let the main thread continue.
Task timeoutTask = new Task(Close); // create a Task around the Close method.
timeoutTask.Start(); // run asynchronously.
bool completedSuccessfully = timeoutTask.Wait(TimeSpan.FromMinutes(1));
if (completedSuccessfully)
{
// Yay!
}
else
{
logger.Write("Close command did not return in time. Continuing");
}
In this example, the Close method will keep on running in the background, but your main thread can continue.

ThreadPool.QueueUserWorkItem versus BeginExecuteNonQuery

I have a problem at work with a simple insert method occasionally timing out due to a scheduled clean-up task on a database table. This task runs every ten minutes and during its execution my code often records an error in the event log due to 'the wait operation timed out'.
One of the solutions I'm considering is to make the code calling the stored procedure asynchronous, and in order to do this I first started looking at the BeginExecuteNonQuery method.
I've tried using the BeginExecuteNonQuery method but have found that it quite often does not insert the row at all. The code I've used is as follows:
SqlConnection conn = daService.CreateSqlConnection(dataSupport.DBConnString);
SqlCommand command = daService.CreateSqlCommand("StoredProc");
try {
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("Customer", customerId);
conn.Open();
command.BeginExecuteNonQuery(delegate(IAsyncResult ar) {
SqlCommand c = (SqlCommand)ar.AsyncState;
c.EndExecuteNonQuery(ar);
c.Connection.Close();
}, command);
} catch (Exception ex) {
LogService.WriteExceptionEntry(ex, EventLogEntryType.Error);
} finally {
command.Connection.Close();
command.Dispose();
conn.Dispose();
}
Obviously, I'm not expecting an instant insert but I am expecting it to be inserted after five minutes on a low usage development database.
I've now switched to the following code, which does do the insert:
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
using (SqlConnection conn = daService.CreateSqlConnection( dataSupport.DBConnString)) {
using (SqlCommand command = daService.CreateSqlCommand("StoredProcedure")) {
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("customer", customerId);
conn.Open();
command.ExecuteNonQuery();
}
}
});
I've got a few questions, some of them are assumptions:
As my insert method's signature is void, I'm presuming code that calls it doesn't wait for a response. Is this correct?
Is there a reason why BeginExecuteNonQuery doesn't run the stored procedure? Is my code wrong?
Most importantly, if I use the QueueUserWorkItem (or a well-behaved BeginExecuteNonQuery) am I right in thinking this will have the desired result? Which is, that an attempt to run the stored procedure whilst the scheduled task is running will see the code executing after the task completes, rather than its current timing out?
Edit
This is the version I'm using now in response to the comments and answers I've received.
SqlConnection conn = daService.CreateSqlConnection(
string.Concat("Asynchronous Processing=True;",
dataSupport.DBConnString));
SqlCommand command = daService.CreateSqlCommand("StoredProc");
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("customer", customerId);
conn.Open();
command.BeginExecuteNonQuery(delegate(IAsyncResult ar) {
SqlCommand c = (SqlCommand)ar.AsyncState;
try {
c.EndExecuteNonQuery(ar);
} catch (Exception ex) {
LogService.WriteExceptionEntry(ex, EventLogEntryType.Error);
} finally {
c.Connection.Close();
c.Dispose();
conn.Dispose();
}
}, command);
Is there a reason why BeginExecuteNonQuery doesn't run the stored
procedure? Is my code wrong?
Probably you didn't add the Asynchronous Processing=True in the connection string.
Also - there could be a situation that when the reponse from sql is ready - the asp.net response has already sent.
that's why you need to use : Page.RegisterASyncTask (+AsyncTimeout)
(if you use webform asynchronous pages , you should add in the page directive : Async="True")
p.s. this line in :
System.Threading.ThreadPool.QueueUserWorkItem is dangerouse in asp.net apps. you should take care that the response is not already sent.

Categories

Resources