I am testing both service broker external activator and polling based client on behalf of process speed performances of each.
For external activator, I have built a command line application which is being notified when any change occur some table and writes to the same db. Code inside exe looks like as follows
private static void ProcessRequest()
{
using (var connection = new SqlConnection(ServiceConstant.ConnectionString))
{
connection.Open();
do
{
using (var tran = connection.BeginTransaction())
{
//Get a message from the queue
byte[] message = QueueProcessorUtil.GetMessage(ServiceConstant.QueueName, connection, tran, ServiceConstant.WaitforTimeout);
if (message != null)
{
MessageReceiving = true;
try
{
//Write it to the db
ProcessMessage(message);
}
catch (Exception ex)
{
logger.Write("Fail: " + ex);
}
tran.Commit();
}
else
{
tran.Commit();
MessageReceiving = false;
}
}
}
while (MessageReceiving);
}
}
When I insert 20 messages to the queue, total duration of insertion of all the messages is approx 10ms
When I extract the ProcessMessage function above which writes the messages to the db to an another separate console application and then call this function 20 times as follows, this time it takes approx 50ms
class Program
{
static void Main(string[] args)
{
for (var i = 1; i <= 20; i++)
{
string message = "mm";
ProcessMessaage(message);
}
}
}
ProcessMessage function
string sql = #"INSERT INTO [Workflow].[dbo].[TestOrderLog]([OrderId],[RecordTime])
VALUES (#orderId, GETDATE()) SELECT SCOPE_IDENTITY()";
using (SqlConnection con = new SqlConnection(ConfigurationManager.AppSettings["SqlConnection"].ToString()))
using (SqlCommand com = new SqlCommand(sql, con))
{
con.Open();
com.CommandType = CommandType.Text;
com.Parameters.AddWithValue("#orderId", 1);
try
{
var result = com.ExecuteScalar();
var id = (result != null) ? Convert.ToInt32(result) : 0;
}
catch (Exception ex)
{
throw ex;
}
con.Close();
}
I don't understand and am surprised although there are costly processing blocks (query a message) inside the loop of external activator code, it takes faster to write db than pure loop in console app code.
Why would pure insertion in a loop be slower than insertion inside the external activator exe instance's code?
Side note, in EAService.config file, <Concurrency min="1" max="1" />
It was an absurd mistake of mine, first one is compiled and deployed running code
and the second one is running with debugger inside visual studio, so the intervals became normal running without debugger.
Related
So I am using c# windows form with visual studio to query an access database.
When I run with debugger and stop the application from within visual studio there is no problem, however when I run WITHOUT debugger, query the database and then close using X, the process which appears under "Apps" in Task manager becomes a background process. I can have multiple instances of this process if I run the application numerous times.
I would appreciate any information on this, Thanks!
Here is the code I am using.
private void BtnSendQuery_Click(object sender, EventArgs e)
{
ReadDatabase();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var x = MessageBox.Show("Are you sure you want to exit? ", "Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (x == DialogResult.No)
{
e.Cancel = true;
}
else
{
e.Cancel = false;
}
}
private void ReadDatabase()
{
string CONNECTION_STR = #"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source = C:\\Users\\***\\Documents\\db_folder\\access_db.accdb;
Persist Security Info = False";
string query = ""; // query string
OleDbConnection DB_CONNECTION = null;
try
{
DB_CONNECTION = new OleDbConnection(CONNECTION_STR);
DB_CONNECTION.Open();
query = TbInputQuery.Text;
var command = new OleDbCommand(query, DB_CONNECTION);
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
DB_CONNECTION.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (DB_CONNECTION != null)
{
DB_CONNECTION.Close();
}
}
}
}
As general rule, both your connection and cmdSQL or reader should be in a using block.
While your reader is in a using block, the ALL important connection object is not.
In fact, once beyond the using block for connection? You could get away not even having using blocks for the command and reader object.
And even if a trapped error, or UN-trapped error occurs? The using block WILL ALWAYS clean up the connection.
So, for command and reader - not end of world for using block.
But, for connection? yes, always do that.
Project->settings - I would use the connection builder for the connection string - not put in code.
eg this one:
Then use advanced, and make sure you choose ACE (for accdb) or JET (for mdb)
So this:
So, with above setting, then we have ONE spot in the system - never typing connecting string by hand or having to place in the code (makes change of connection very hard).
Also, don't use "any cpu" force the project to x86 for using Access x32
(or if using x64, then force project to that).
So, code say like this:
private void ReadDatabase()
{
string CONNECTION_STR = Properties.Settings.Default.AccessDB;
string query = ""; // query string
try
{
using (OleDbConnection DB_CONNECTION = new OleDbConnection(CONNECTION_STR))
{
using (OleDbCommand command = new OleDbCommand(query, DB_CONNECTION))
{
DB_CONNECTION.Open();
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
}
}
Note in above - don't really care about the catch block - as long as the using block for the connection is built - it gets cleaned up no matter what - and even if no try/catch, or if in fact you have one!!
And if a error trigger - still again, note how we do NOT have to clean up, or close the connection.
I have a code to asynchronously update multiple rows in SQL Server's table. I tested it on updating 540 rows and 144 rows are updated in the table instanly, then it waits for about 5 minutes and then the rest is updated. At least this is how it looks when I check for updated rows with SELECT.. I'm wondering why is that.
The whole thing is triggered by button's click:
DialogResult res = MessageBox.Show($"Znaleziono {num} pasujących maszyn. Czy chcesz zaktualizować priorytet maszyny danymi z pliku?", "Potwierdź", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(res == DialogResult.Yes)
{
await UpdatePriority();
MessageBox.Show("Updated!");
Here's UpdatePriority method that asynchronously call place.Edit() method for all places in the list of items:
public async Task<string> UpdatePriority()
{
List<Task<string>> UpdateTasks = new List<Task<string>>();
try
{
foreach (Place p in Items.Where(i => i.IsUpdated==true))
{
UpdateTasks.Add(Task.Run(()=> p.Edit()));
}
string response = "OK";
IEnumerable<string> res = await Task.WhenAll<string>(UpdateTasks);
}
catch (Exception ex)
{
throw;
}
return "Nie udało się zaktualizować danych żadnego zasobu..";
}
And here is Edit() method of place object. It basically updates place data in SQL server table:
public async Task<string> Edit()
{
string iSql = #"UPDATE JDE_Places
SET Priority=#Priority
WHERE PlaceId=#PlaceId";
string msg = "OK";
using (SqlCommand command = new SqlCommand(iSql, Settings.conn))
{
command.Parameters.AddWithValue("#PlaceId", PlaceId);
command.Parameters.AddWithValue("#Priority", Priority);
int result = -1;
try
{
result = await command.ExecuteNonQueryAsync();
IsUpdated = false;
}
catch (Exception ex)
{
msg = $"Wystąpił błąd przy edycji zasobu {Name}. Opis błędu: {ex.Message}";
}
}
return msg;
}
And here's Settings conn property that serves as reusable connection object:
public static class Settings
{
private static SqlConnection _conn { get; set; }
public static SqlConnection conn
{
get
{
if (_conn == null)
{
_conn = new SqlConnection(Static.Secrets.ConnectionString);
}
if (_conn.State == System.Data.ConnectionState.Closed || _conn.State == System.Data.ConnectionState.Closed)
{
try
{
_conn.Open();
}
catch (Exception ex)
{
MessageBox.Show("Nie udało się nawiązać połączenia z bazą danych.. " + ex.Message);
}
}
return _conn;
}
}
}
I realize it's probably better to keep the connection within using statement (instead of reusing it), but when I added it to place.Edit() method it worked even slower (and unreliably).
UPDATE: I ran few tests more and the time they took to add 540 rows varied from 15 seconds to 400 seconds.. Then I just changed result = await command.ExecuteNonQueryAsync() to result = command.ExecuteNonQuery() in Edit() of place object, ran few tests more, and all finished under 10 seconds! I don't know why async version of ExecuteNonQuery() was so much worse than non-async one, though. Single Edit() method was taking around 0,1 sec with ExecuteNonQuery() and 1 - 400 seconds with ExecuteNonQueryAsync(). Here are logs: ExecuteNonQuery() ExecuteNonQueryAsync()
Your issue here is your Settings class. You're essentially trying to use the same SqlConnection object in multiple Sqlcommands. SqlConnection is not threadsafe when used like this. You end up with multiple commands because your code is non-blocking and async. That is what is causing your code the "wait" (or deadlock). This is why when you run it sync (without the ExecuteNonQueryAsync, etc.) it works correctly.
You don't need this object at all anyway. ADO.Net handles connection pooling for you, so there is no advantage in re-using the same SqlConnection. Just create a new one for each SqlCommand:
public async Task<string> Edit()
{
using (SqlConnection conn = new SqlConnection(...))
using (SqlCommand command = new SqlCommand(iSql, conn))
{
...
}
}
and you should find that your "wait" goes away.
i have an notification application built in c# for notifying any change in database . the application runs in the background . But the problem is after the start of the application if the internet is switched off the application throws an SQLException . i have used try catch to handle the exception . but i want my application to try connecting the database and when the connection is established it returns to the main code .
try
{
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
//i want to return here when the connection is reestablished
using (SqlCommand command =
new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
// Make sure we don't time out before the
// notification request times out.
command.CommandTimeout = NotificationTimeout;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
messageText = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13)).ToString();
// Empty queue of messages.
// Application logic could parse
// the queue data and
// change its notification logic.
}
object[] args = { this, EventArgs.Empty };
EventHandler notify =
new EventHandler(OnNotificationComplete);
// Notify the UI thread that a notification
// has occurred.
this.BeginInvoke(notify, args);
}
}
}
catch(SqlException e)
{
}
is it possible to do it without goto statement . i would prefer avoiding the goto statement .
I would move the retry logic out of the query method. I've seen a good retry library somewhere, but I can't find it just now.
public void StartListener()
{
var message = GetMessage();
//process message in some way
object[] args = { this, EventArgs.Empty };
EventHandler notify = OnNotificationComplete;
this.BeginInvoke(notify, args);
}
private const int TimeoutStep = 2000;
private const int MaxTimeout = 10000;
private string GetMessage(int timeout = 0)
{
//prevent loop of endless retries
if (timeout >= MaxTimeout)
{
//optional: define your own Exception class
throw new MaxTimeoutException();
}
try
{
Thread.Sleep(timeout);
return GetMessageFromDatabase();
}
catch (SqlException ex)
{
//log ex in debug mode at least
return GetMessage(timeout + TimeoutStep);
}
}
private string GetMessageFromDatabase()
{
string message = null;
using (var connection = new SqlConnection(GetConnectionString()))
{
using (var command = new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
command.CommandTimeout = NotificationTimeout;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
message = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13));
}
}
}
}
return message;
}
from the suggestion of #Archer i got the solution . in the catch block i call the method again which uses this connection after some suitable time . Something like
public void StartListener()
{
try
{
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
//i want to return here when the connection is reestablished
using (SqlCommand command =
new SqlCommand(GetListenerSQL(), connection))
{
connection.Open();
// Make sure we don't time out before the
// notification request times out.
command.CommandTimeout = NotificationTimeout;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
messageText = System.Text.ASCIIEncoding.ASCII.GetString((byte[])reader.GetValue(13)).ToString();
// Empty queue of messages.
// Application logic could parse
// the queue data and
// change its notification logic.
}
object[] args = { this, EventArgs.Empty };
EventHandler notify =
new EventHandler(OnNotificationComplete);
// Notify the UI thread that a notification
// has occurred.
this.BeginInvoke(notify, args);
}
}
}
catch(SqlException e)
{
Thread.Sleep(2000);
StartListener();
}
}
If its an failure you should call an timer and the timer should call the backgroundworker.
Write the Functionality to check the connection in the backgroundworkers. if it goes for true you should stop the timer. And call the usual process
How about!, someone could help me with this please, what I'm looking for is that through a console application every time the "00" minutes (that is, every hour), the stored procedure is executed only once (I do not know why it runs more than 1 time, since it is an insertion procedure)and I also want the application never to close, later I want to create a service and execute more procedures, but I need this for while. What am I doing wrong ?, the idea is that in the console write "Waiting for insertion in batch" and when the time comes, execute the procedure and write "Successful insertion", then keep typing "Waiting for insertion in batch" until the next hour arrives.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
namespace Job_StoreProcedure
{
class Program
{
static void Main(string[] args)
{
using (SqlConnection conn = new SqlConnection
("Server=localhost\\SQLEXPRESS;Database=VIDEOJUEGOS;Integrated Security=SSPI"))
{
conn.Open();
for (int i = 0; i - 1 < i++; i++)
{
Console.WriteLine("Waiting for insertion in batch");
if (DateTime.Now.ToString("mm") == "00")
{
SqlCommand cmd = new SqlCommand("usp_virtualX", conn);
cmd.CommandType = CommandType.StoredProcedure;
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine("Successful insertion");
}
}
}
}
}
}
}
}
As mentioned in comments best way to meet your needs is remove the loop and perform the operation only once, and create a task schedule to run the program on required time.
If you need to continue with same approach some of the problems which this code must be facing:
Each hour it would insert more than once if insert operation takes less than a minute. Example: say if the insert starts at 1:00:00 and finishes at 1:00:20, the program will start next iteration and would insert again because mm is still 00. One of the solution is to put the thread to sleep for 1 minute from inside of outer loop.
You will face one more problem with this code that connection would close when remains unused for some time. Also when insertion fails program will exit because of no error handling. You might want to open and close connection while performing operation (i.e. inside loop), and use error handling to keep the application running in case of exception.
Just use the timers.
using System.Timers;
//...
class Program
{
private static Timer MainTimer = new Timer(1000 * 60 * 60);
static void Main(string[] args)
{
Console.WriteLine("Waiting for insertion in batch");
MainTimer.Elapsed += MainTimer_Elapsed;
// Wait for the start of the hour. Then start the one-hour MainTimer.
var tmptimer = new Timer() { Interval = 1000 };
tmptimer.Elapsed += (sender, e) =>
{
if (DateTime.Now.Minute == 0)
{
MainTimer.Start();
tmptimer.Stop();
MainTimer_Elapsed(null, null); // Call manually first time
}
};
tmptimer.Start();
while (true)
Console.Read();
}
private static void MainTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (SqlConnection conn = new SqlConnection ("Server=localhost\\SQLEXPRESS;Database=VIDEOJUEGOS;Integrated Security=SSPI"))
{
conn.Open();
SqlCommand cmd = new SqlCommand("usp_virtualX", conn);
cmd.CommandType = CommandType.StoredProcedure;
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine("Successful insertion");
}
}
}
Console.WriteLine("Waiting for insertion in batch");
GC.Collect();
}
}
This becomes considerably easier if you adopt async/await and use Task.Delay:
For instance, you can:
static async Task Main(string[] args) //async Main supported in C#7
{
var now = DateTime.UtcNow; //always use UTC, calculating timezones costs time
var startOfCurrentTimePeriod =
new DateTime(now.Year,
now.Month,
now.Day,
now.Hour,
now.Minute,
now.Second,
0, //set this ms part to 0
DateTimeKind.Utc);
var triggerTime = oClock.AddSeconds(1); //when we want to run our action
while (true)
{
var waitTime = triggerTime - DateTime.UtcNow;
if (waitTime > TimeSpan.Zero) //if we have a negative wait time, just go
{
await Task.Delay(waitTime);
}
triggerTime = triggerTime.AddSeconds(1); //set the next time
//perform action
Console.WriteLine($"the time is : {triggerTime}");
}
}
It should be trivial to convert this code to trigger on the hour rather than on the second. A good exercise.
I have implemented SqlClient connecting function with timeout parameter. It means, that connection.open() is in another thread and after thread is started, I'm checking elapsed time. If the time had reached timeout, thread is aborted and no connection is established.
The thing is, that if I have timeout bigger then default connection.open() timeout, open() throws SqlException, which isn't caught in my Catch(SqlException) block.
I'm starting whole connecting process in another thread:
public void connect()
{
Thread connectThread = new Thread(waitForTimeout);
connectThread.Start();
}
Connecting thread -> starts another thread for timeout waiting
public void waitForTimeout()
{
connection = new SqlConnection(connectString);
Thread timeoutThread = new Thread(openConnection);
timeoutThread.Start();
DateTime quitTime = DateTime.Now.AddMilliseconds(timeout);
while (DateTime.Now < quitTime)
{
if (connection.State == ConnectionState.Open)
{
transac = connection.BeginTransaction();
command = connection.CreateCommand();
command.Transaction = transac;
break;
}
}
if (connection.State != ConnectionState.Open)
timeoutThread.Interrupt();
}
Here exception isn't caught after open() default timeout:
private void openConnection()
{
try
{
connection.Open();
}
catch(SqlException ex)
{
// This isn't caught anytime
}
}
Thank you for any ideas!
Isn't it caught or isn't it thrown? Thread.start only schedules the thread for running but doesn't mean it will start immediately. Maybe code runs till threadTimeout interruption, then openConnection starts and always succeed to open the connection within default timeout.
---edit
In this case maybe could you try to:
replace SqlException by Exception and check if you catch something such as ThreadInterruptedException instead
put the content of openConnection method in your waitForTimeout method right after connection = new SqlConnection(connectString); (and comment the rest of the code) and see if exception is still not handled. If not, then put it in the connect() method and check again.
After comments I tried to implement new solution, and here it is:
Constructor:
/* ------------------------------------------------------------------------- */
public Database(string source, string database, string user, string password,
int timeout, DelegateConnectionResult connectResult)
{
this.timeout = timeout;
this.connectResult = connectResult;
connectString = "server=" + source +
";database=" + database +
";uid=" + user +
";pwd=" + password +
";connect timeout=" + Convert.ToInt16(timeout / 1000);
}
Asynchonous connect:
/* ------------------------------------------------------------------------- */
public void connectAsync()
{
connectThread = new Thread(connectSync);
connectThread.Start();
}
Synchronous connect:
/* ------------------------------------------------------------------------- */
public void connectSync()
{
connection = new SqlConnection(connectString);
try
{
connection.Open();
transac = connection.BeginTransaction();
command = connection.CreateCommand();
command.Transaction = transac;
if (connection.State == ConnectionState.Open)
connectResult(true);
else
connectResult(false);
}
catch
{
connectResult(false);
}
}
And I found the solution for original problem witch SqlException from this post: it has something to do with Exceptions settings in debugger of Visual Studio. If I unchecked "throw" choice at SqlException in Exceptions list (CTRL + D + E in Visual Studio), I'm finally able to catch exception.