Delay to SQL Server throw an exception - c#

I have this Code to Get a table Data From SQL Server:
public static System.Data.Linq.Table<Equipment> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
I Have a Button to call this Function :
private void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = GetEquipmentTable();
}
My Problem is :When I Disable Communication Between my App and SQL Server Machine and then click this button, It takes a while to throw an Exception that Connect to Database is impossible!!!! My major problem is that my app freezed till this Exception accrued.
Did I missed something ?
Update 1 :
I used async and wait base on Rahul solution
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}
but it still wait for this line of code :
return dc.GetTable<Equipment>();
and UI freezes as well.
I think dc.gettable<> is not waitable or somthing else !!??

When I Disable Communication Between my App and SQL Server Machine and
then click this button
That's obvious right since it tries to connect to the machine (within the Timeout mentioned in connection string) and then throws the exception back once it finds that the server isn't reachable.
major problem is that my app freezed till this Exception accrued
Probably in that case make the method as async method like
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
Your event handler
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}

You have two problems, the app freezing is because you are not using asynchronous programming.
The delay before the connection exception is because the client side app waits until the connection timeout timer finishes (30 seconds default).
Try using async await on your database calls to free up the UI.
Try changing the connection timeout to 5 seconds in the connection string.
Change in connection string:
"Data Source=...;Connect Timeout=5"

Use await as in the answer from Rahul. +1
You could also test a simple SqlConnection.Open
private static bool OpenSqlConnection(string connectionString)
{
bool return = false;
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
return = true;
}
catch (Exception ex)
{
return = false;
}
finally
{
connection.Close();
}
return return;
}
Could use SqlConnection.OpenAsync.
SqlConnection con = new SqlConnection("connection string");
bool resp = false;
try
{
con.OpenAsync();
resp = true;
}
catch (SqlException ex)
{
//use the ex message
resp = false;
}
catch (Exception ex)
{
resp = false;
}
finally
{
con.Close();
}

Related

how to make progress bar work with functions in button event

i am new in C# so please be patient with me .
i want to make progress bar work with any functions i make in my program
i have class to check if INTERNET available and the connection of database status
and i have "progressBar1" , style is "Marquee"
i just want to indicate that there is a process work "Function" in the program and i don't need to have step or timer to increment it
just make the progress work until the function finish its code and the functions will work in button event (when i push button)
this is my code
class checkInternet
{
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public bool checkInternetAvailable()
{
int Desc;
bool result = false;
if (InternetGetConnectedState(out Desc, 0) == true)
{
try
{
dbConnection StartConn = new dbConnection();
SqlConnection MyConnetion = StartConn.GetConnection();
MyConnetion.Open();
if (MyConnetion.State == ConnectionState.Open)
{
result = true;
}
MyConnetion.Close();
}
catch (Exception)
{
result = false;
MessageBox.Show("The database connection does not available, May be because of this reasons: \n\n1- there is a new version of the program avalible. \n2- database has some maintenance. \n\n Please check later :)", "Conection status");
}
}
else
{
result = false;
MessageBox.Show("No internet connection avalible , Please check later :) \nThanks.", "Conection status");
}
return result;
}
}
and this is what i have in my button event
private void button1_Click(object sender, EventArgs e)
{
checkInternet check = new checkInternet();
progressBar1.Value = 0;
do
{
progressBar1.PerformStep();
} while (check.checkInternetAvailable());
}
how can i implement that ?
thanks
As I understand you want user to see progressbar while your check connection task executes in background. checkInternetAvailable would be your background operation and I wouldn't suggest showing messages directly form it. Instead return a custom struct :
public struct ConnectionCheckResult
{
public bool Success;
public string Message;
}
And this will be your button click event handler :
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = true;
//add code here to be executed on UI thread before connection check
Task.Run(new Action(() =>
{
//Task.Run this code on the thread pool instead of your UI thread. So your code is checking connection while progress bar is still rendering
ConnectionCheckResult res = new checkInternet().checkInternetAvailable();
this.Invoke(new Action(() =>
{
//this.Invoke executes following delegate on UI thread. All UI changes - like progressBar1.Visible = false; need to be made in UI thread.
//add code here to be executed on the UI thread after connection check.
progressBar1.Visible = false;
if (!string.IsNullOrEmpty(res.Message))
MessageBox.Show(res.Message);
}));
}));
//add code to be executed on UI thread at the same time as connection check
}
I know multi-threading is difficult to wrap your head around at first, here's good tutorial with code samples.
Also when your progressbar style is Marquee you don't need to call PerformStep. It will just roll by itself.
EDIT: You should also modify checkInternetAvailable() like so :
public ConnectionCheckResult checkInternetAvailable()
{
int Desc;
ConnectionCheckResult result = new ConnectionCheckResult();
if (InternetGetConnectedState(out Desc, 0) == true)
{
try
{
dbConnection StartConn = new dbConnection();
SqlConnection MyConnetion = StartConn.GetConnection();
MyConnetion.Open();
if (MyConnetion.State == ConnectionState.Open)
{
result.Success = true;
}
MyConnetion.Close();
}
catch (Exception)
{
result.Success = false;
result.Message = "The database connection does not available, May be because of this reasons: \n\n1- there is a new version of the program available. \n2- database has some maintenance. \n\n Please check later :)";
}
}
else
{
result.Success = false;
result.Message = "No internet connection available , Please check later :) \nThanks.";
}
return result;
}

Calling a MySQL Routine in C#

Please accept my apologies if I'm getting my verbiage wrong; I'm just now learning C# (my background is mostly Visual Basic and PHP).
What I'm trying to do is create a class / routine in C# (Windows Forms) for connecting and disconnecting to a MySQL database that can then be reused throughout the rest of my project without having to reiterate the code every time.
I've got my class / routine setup, but I'm stuck on trying to call it from the rest of my project. I know in Visual Basic this was a fairly simple task to do, but I just can't seem to figure it out how to do it in C#.
Any suggestions? Thank you in advance.
public void dbDisconnect(object sender, EventArgs e)
{
try
{
MySqlConnection connection = new MySqlConnection(Properties.Settings.Default.mysql_db_conn_string);
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here's a method I currently have in my app:
public static MySqlConnection CreateConnection(
string mysqlServer,
string mysqlUser,
string mysqlPassword,
string mysqlDatabase)
{
MySqlConnection mysqlConnection = null;
string mysqlConnectionString = String.Format(
"server={0};uid={1};pwd={2};database={3};DefaultCommandTimeout={4};",
mysqlServer, mysqlUser, mysqlPassword, mysqlDatabase, 120);
/**
** Workaround for MySQL 5.6 bug:
** http://stackoverflow.com/questions/30197699/reading-from-stream-failed-mysql-native-password-error
*/
int tryCounter = 0;
bool isConnected = false;
do
{
tryCounter++;
try
{
mysqlConnection = new MySqlConnection();
mysqlConnection.ConnectionString = mysqlConnectionString;
mysqlConnection.Open();
if (mysqlConnection.State == ConnectionState.Open)
{
isConnected = true;
}
}
catch (MySqlException ex)
{
if (tryCounter < 10)
{
DebugLog.Dump(ex.ToString(), DebugLog.MainLogFilePath);
Thread.Sleep(10000); // 10 seconds.
}
else
{
throw;
}
}
} while (!isConnected);
return mysqlConnection;
}
Usage:
using (MySqlConnection hostsDbConnection = HostsDbConnector.CreateConnection())
{
// Do something...
}
With using keyword you don't need to close the connection manually, it'll be closed automatically when it's no longer needed.

Progress bar not working on button click C# windows application

I want to synchronize my local and web database so i have written a stored procedure using linked server. My stored procedure executes fine and data synchronization is successful but the procedure takes around 7-10 minutes to get executed. The exact timing cannot be determined. So whenever the procedure runs on my windows application then the page seems as if it has become unresponsive though the process is still going on.
So i am having a "Data Sync" button on my page on click of which i want the progress bar to display the progress of the stored procedure. For the time being I am taking the average of last few execution timings to define the time duration for which the stored procedure runs. Now the problem is that when i click on the data sync button then the progress bar doesn't work. Kindly help me with this issue.
My code is as follows:-
namespace RMS
{
public partial class DataSync : Form
{
connection con = new connection();
SqlCommand cmd = new SqlCommand();
static int rowCount;
static int syncTime;
static int timeSlice;
public DataSync()
{
InitializeComponent();
}
private void btnDataSync_Click(object sender, EventArgs e)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
try
{
con.GetConnectLive();
con.GetConnect();
if (con.CnLive.State == ConnectionState.Open)
{
MessageBox.Show("Connection to Live Server Successful!!!...Data Synchronisation may take several minutes so do not cancel the operation while in execution mode");
btnDataSync.Enabled = false;
btnDataSync.Text = "Please Wait...";
string Str = "RMS_LocalToLive";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
rowCount = cmd.ExecuteNonQuery();
if (rowCount > -1)
{
MessageBox.Show("Total no. of rows synchronised = " + rowCount);
btnDataSync.Text = "Success";
}
else
{
MessageBox.Show("Data Synchronisation couldn't be completed because of connection problem... Please try again!!!");
}
}
else
{
MessageBox.Show("Unable to connect to Live Server...Please check your internet connection and try again!!!");
}
con.GetDisConnect();
con.GetDisConnectLive();
}
catch (Exception ex)
{
MessageBox.Show("Please check your internet connection and try again!!!");
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
con.GetConnect();
string Str = "RMS_DataSyncTime";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
syncTime = Convert.ToInt32(cmd.ExecuteScalar().ToString());
timeSlice = syncTime / 100;
con.GetDisConnect();
}
catch (Exception ex)
{
MessageBox.Show("Unable to retrieve last Data Synchronisation Timing");
}
for (int i = 1; i <= synctime; i=i+timeslice)
{
Thread.Sleep(timeslice);
// Report progress.
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString() + "% Completed";
}
private void DataSync_Load(object sender, EventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgse)
{
}
}
}
The main issue here is that, while you are executing your progress bar updates in the BackgroundWorker's thread, the ReportProgress() updates never make it to the UI thread, because you've blocked that thread with the main SQL operation.
Instead of doing that, you should do something more like this:
private void btnDataSync_Click(object sender, EventArgs e)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
btnDataSync.Enabled = false;
btnDataSync.Text = "Please Wait...";
bool success = false;
try
{
// Execute the query asynchronously
success = await Task.Run(() => ExecuteLocalToLive());
}
catch (Exception ex)
{
MessageBox.Show("Please check your internet connection and try again!!!");
}
btnDataSync.Enabled = true;
btnDataSync.Text = success ? "Success" : "Failure";
}
private bool ExecuteLocalToLive()
{
bool success = false;
con.GetConnectLive();
con.GetConnect();
if (con.CnLive.State == ConnectionState.Open)
{
MessageBox.Show("Connection to Live Server Successful!!!...Data Synchronisation may take several minutes so do not cancel the operation while in execution mode");
string Str = "RMS_LocalToLive";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
rowCount = cmd.ExecuteNonQuery();
if (rowCount > -1)
{
MessageBox.Show("Total no. of rows synchronised = " + rowCount);
success = true;
}
else
{
MessageBox.Show("Data Synchronisation couldn't be completed because of connection problem... Please try again!!!");
}
}
else
{
MessageBox.Show("Unable to connect to Live Server...Please check your internet connection and try again!!!");
}
con.GetDisConnect();
con.GetDisConnectLive();
return success;
}
I have rearranged the code that handles the button state and text, so that it's still executed in the UI thread where it belongs, even though the method itself is not. You also never appeared to set the button back to the enabled state; it's not clear to me whether that was intentional or not, so I went ahead and added a line to do that.
Finally, I will strongly recommend you figure out a better way to report status to the user than the calls to MessageBox.Show() you have now. The biggest issue is that you don't even start doing any work until after the user dismisses the initial message, which immediately puts your progress bar out of sync with the actual work. But it's also better to keep all your UI in the UI thread, and to keep UI separate from non-UI logic (i.e. the SQL operation).

TCPIP connection in c# and data sending/receiving in another threads

I have a problem with my TCPIP connection Form programm.
I have a code, where I'm trying to send and receive some data from server.
The main problem of my app is how to reconcile some threads:
myListenThread - to listening data from server
myReadStreamThread - to read data from server
System.Threading.Thread - main thread eg. to write data to server
captureThread - to do another things like capturing images from camera
Part of my code:
private void buttonConnect_Click(object sender, EventArgs e)
{
try
{
Connect();
Connected = true;
this.myListenThread = new Thread(new ThreadStart(Listen));
this.myListenThread.Start();
}
catch
{
MessageBox.Show("Invalid host! Try again.");
}
}
private void Listen()
{
this.myReadStreamThread = new Thread(new ThreadStart(ReadStream));
this.myReadStreamThread.Start();
while (Connected)
{
if (!myReadClient.Connected)
{
Connect();
}
}
}
private void Connect()
{
IPAddress IP = IPAddress.Parse(textboxIP.Text);
int PORT = Convert.ToInt32(textboxPORT.Text);
this.myReadClient = new TcpClient();
this.myReadClient.Connect(IP, PORT);//SOMETIMES HERE'S AN ERROR
this.myStream = this.myReadClient.GetStream();
Properties.Settings.Default.IP = Convert.ToString(IP);
Properties.Settings.Default.PORT = Convert.ToString(PORT);
Properties.Settings.Default.Save();
}
private void ReadStream()
{
while (true)
{
try
{
this.myReadBuffer = new byte[this.myReadClient.ReceiveBufferSize];
this.myBufferSize = myStream.Read(myReadBuffer, 0, this.myReadClient.ReceiveBufferSize);
if (myBufferSize != 0)
{
this.myString = Encoding.ASCII.GetString(myReadBuffer);
//myDelegate myDel;
//myDel = new myDelegate(Print);
//richtextboxRead.Invoke(myDel);
}
}
catch
{
break;
}
}
}
All is working correct when I'm connecting to server, but when I want to send some string the problem appears because of threads.
I decided to send string, by clicking Button3 and waiting until I receive string "1" from server using while loop:
private void button3_Click(object sender, EventArgs e)
{
this.captureThread = new Thread(new ThreadStart(() => this.newGame()));
this.captureThread.Start();
}
private bool newGame()
{
string command = "12345abc";
if (Connected)
{
WriteStream(command);
}
while (myBufferSize == 0 && myString !="1") { }
Thread.Sleep(2000);
...//doing other things
}
private void WriteStream(string command)
{
Connect();
this.myWriteBuffer = Encoding.ASCII.GetBytes(command);
this.myStream.Write(this.myWriteBuffer, 0, command.Length);
}
And the problem with connection and data send/receive problem appears, when it should write my string "command" - it doesn't react. MyBufferSize is always 0 and myString is always null. Sometimes an Error about connection appears when I click Button3 (assigned in code). I think it is because in captureThread I can't see any data from another threads. How to solve it?

Cancelling a background worker which is continuously reading from a network stream

I have a TCP server running which spits out messages of 2 bytes at regular intervals.
I'm trying to create a client side form which connects to the server and continuously reads from the stream until I click a disconnect button on the form.
So far the client works fine except that I cannot disconnect. I set the CancellationPending to true but it seems to reset back to false before the dowork method gets a chance to set e.Cancel.
I'm also sure there must be a more acceptable way of continuously reading the stream and writing to the form - at the moment I am calling RunWorkerAsync within the Worker Completed method to achieve the loop!
private void Disconnect()
{
commsWorker1.CancelAsync();
}
private void ReadFromStream()
{
try
{
commsWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
writeToBox("Error: " + ex.Message);
}
}
//background worker dowork method
private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
{
if (true == commsWorker1.CancellationPending)
{
e.Cancel = true;
}
else
{
Byte[] dataArray = new Byte[2];
try
{
_DataStream.Read(dataArray, 0, 2);
String reply = System.Text.Encoding.ASCII.GetString(dataArray);
e.Result = reply;
}
catch (Exception ex)
{
}
}
}
//background worker workercompleted method
private void BackGroundDisplayMessages(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
//close connection here
}
else
{
writeToBox((String)e.Result);
commsWorker1.RunWorkerAsync();
}
}
}
}
Can't you just loop inside the background worker method?
private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
{
while(true)
{
Byte[] dataArray = new Byte[2];
try
{
_DataStream.Read(dataArray, 0, 2);
String reply = System.Text.Encoding.ASCII.GetString(dataArray);
e.Result = reply;
}
catch (Exception ex)
{
return;
}
}
}
Then upon disconnect simply close the socket. This will cause the Exception to be thrown in the while loop and you can exit gracefully through the catch block.
Edit: Then you can update the GUI from the loop after each message is read. Make sure the handle to the control you are updating is available (assuming it's called box):
delegate void updateDelegate(String p);
private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
{
while(true)
{
Byte[] dataArray = new Byte[2];
try
{
_DataStream.Read(dataArray, 0, 2);
String reply = System.Text.Encoding.ASCII.GetString(dataArray);
box.BeginInvoke(new updateDelegate(writeToBox), reply);
}
catch (Exception ex)
{
return;
}
}
}
BeginInvoke is required in this case because you are trying to update the GUI from another thread, which is not allowed. This method forwards the update to the GUI thread.
It seems that you are invoking RunWorkerAsync() in the worker complete method and that resets your CancellationPending prop. I think you can try to fix this by adding to Disconnect() method some disconnectFlag = true; and in WorkerComplete method you should add:
if (e.Cancelled || disconnectFlag)
{
disconnectFlag = false;
//close connection here
} else ...

Categories