BackgroundWorker doesn't handle exception - c#

I've really read all other similar threads on Stackoverflow. Nothing works for me...
I throw an exception of type "Exception" but i can't handle the exception.
I've tried it in the DoWork Progress, in the CompletedEvent (with try/catch, witch e.error....)
void bgGetResponse_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
ConvertByte(myFile);
myFile= null;
}
}
void bgGetResponse_DoWork(object sender, DoWorkEventArgs e)
{
byte[] test= new byte[] { 1, 1, 0, 1, 1};
//Here the error occured (just with throw new Exception("error"))
//The method only throws an exception (for test purposes)
testResponse= _configManager.GetResponse(test, 0);
}
GetResponse(...)
{
throw new Exception("..!");
}
Any ideas?
Thanks for your efforts

I usually just catch it in the work Method and set the result to it.
private void BGW_DoWork(object sender, DoWorkEventArgs e)
{
...
}
catch (Exception ex)
{
e.Result = ex;
}
Then look in the Completed event,
private void BGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Cursor = Cursors.Default;
try
{
Exception ex = e.Result as Exception;
if (null != ex)
throw ex;
...

If by "can't handle" the exception you mean can't use catch, that's true. You just use the Error property. You could "throw" that in your Completed event handler; but then you stack frame will be different.
e.g.:
try
{
if(e.Error != null) throw(e.Error)
// handle success case
}
catch(MyException exception)
{
// handle specific error.
}

Any unhandled exceptions occuring in the BackgroundWorkers DoWork function will cause the worker to fire RunWorkerCompleted where the event argument will contain the error.

Related

C# Global exception handler

This question has been answered a thousand times but although I've tried everything, I can't seem to get my Global Exception Handler to work.
I'm using a windows form with several async methods. All my async methods are wrapped in try catch blocks and handled accordingly. I also have every block of code where I expect an exception wrapped in a try catchblock.
I'm interested in using a global exception handler to catch exceptions that I'm not expecting so that I can log them and let the user know there has been an exception before safely closing down the program.
In Main() I have the following:
[STAThread]
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
static void Main()
{
crashLogInit = InitLogExceptions(); // sets global exception handlers and returns true if successful.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainWindow = new MainWindow(); // My window
LoadSaveManager.Init(); // initiates all relavent components for saving and loading data.
if (isLoaded() && crashLogInit) // Loads data and checks it is successful, also checks global exception handlers are set.
{
RunProgram(); //Method which does Application.Run(MainWindow);
}
else
{
MessageBox.Show(Form.ActiveForm, "Error while starting application!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
CloseResources();
}
}
In the InitLogExceptions() I have the following:
private static bool InitLogExceptions()
{
try
{
crashlogPath = Path.Combine(Directory.GetCurrentDirectory(), crashlogName);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
return true;
}
catch { return false; }
}
In MainWindow() I have a button which fires a clicked event which throws an ArgumentNullException which is getting caught by the debbugers own exception handler but isnt getting caught by any of mine nor is it getting logged.
Below is the code for my exception handlers:
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
ShowException(sender, e.Exception, true);
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ShowException(sender, e.ExceptionObject as Exception, true);
}
public static void ApplicationHandler(object sender, Exception e)
{
if (!crashLogInit) { InitLogExceptions(); }
ShowException(sender, e, false);
}
public static void ApplicationHandler(object sender, Exception e, bool forceClose)
{
if (!crashLogInit) { InitLogExceptions(); }
ShowException(sender, e, forceClose);
}
private static bool WriteToLog(object sender, Exception exception)
{
try
{
DateTime dateTime = DateTime.Now;
StreamWriter writer = File.AppendText(crashlogPath);
string date = dateTime.ToString("yyyy-MM-dd # HH:mm:ss");
writer.WriteLine(date + ":");
writer.WriteLine();
writer.WriteLine();
writer.Write($" SENDER: {sender.GetType().ToString()} EXCEPTION MESSAGE: {exception.Message}");
writer.WriteLine(exception.Source == null ? "" : $"SOURCE: {exception.Source}");
writer.WriteLine();
writer.WriteLine(exception.StackTrace == null ? exception.InnerException.StackTrace : exception.StackTrace);
if (exception.GetType().IsSubclassOf(typeof(AppExceptions)))
{
writer.WriteLine();
writer.WriteLine($"ORIGINAL MESSAGE: {exception.InnerException.Message} ORIGINAL SOURCE: {exception.InnerException.Source}");
}
writer.WriteLine();
writer.WriteLine();
writer.Close();
return true;
}
catch (Exception)
{
return false;
}
}
private static void ShowException(object sender, Exception e, bool forceClose)
{
StringBuilder output = new StringBuilder();
if (WriteToLog(sender, e))
{
output.AppendLine($"Copied to Crashlog! Location of Crashlog file: {crashlogPath}");
output.AppendLine();
output.AppendLine("Send Crashlog to developer!");
}
else
{
output.AppendLine("Could not copy to Crashlog!");
}
output.AppendLine();
output.AppendLine(forceClose ? "Application will now close!" : "Application will now continue at user's own risk!");
MessageBox.Show(Form.ActiveForm, output.ToString(), e.Message.ToUpper() + "!", MessageBoxButtons.OK, MessageBoxIcon.Error);
if (forceClose)
{
Environment.FailFast(e.Message, e);
}
}
Exceptions else where are working and getting logged except this simple thrown exception on a button clicked. What am I doing wrong?

function calling sequence disturbed due to exception

It may sound very basic but I am stuck in a situation where the function calling sequence is being disturbed due to exception even after exception handling.
I have the following situation in my windows form project (C#) (dummy code only):
private void timer1_Tick(object sender, EventArgs e)
{
try
{
BAL objBAL = new BAL();
objBAL.BL_Function1();
objBAL.BL_Function2();
objBAL.BL_Function3();
objBAL.BL_Function4();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
the above functions are called from the business logic(BL) class which further has function callings of various functions of Data Access Layer (DAL) class.
Now the problem is whenever exception comes in any of the above functions, let's say BL_Function3(), it resets the calling to BL_Function1() which leaves BL_Function4() uncalled, which is not desirable.
My question is:
Is there any way to persists the calling sequence, i.e., if exception occurs at BL_Function2(), it should go ahead and call BL_Function3() and BL_Function4(), and then return back to BL_Function1() in the next timer_tick ?
Any help on this would be appreciated.
You can wrap each method into try..catch:
private void timer1_Tick(object sender, EventArgs e) {
//TODO: you may want to stop timer here...
BAL objBAL = new BAL();
try {
objBAL.BL_Function1();
}
catch (Exception ex) { //TODO: catch more specific exception (not Exception)
// If BL_Function1() fails, show message...
MessageBox.Show(ex.Message);
}
// ...and go ahead
try {
objBAL.BL_Function2();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
try {
objBAL.BL_Function3();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
try {
objBAL.BL_Function4();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
//...and restart the timer here
}
Edit: please note, that the timer keep on ticking when MessageBox is on the screen. You may want to stop the timer for a while and then restart it:
private void timer1_Tick(object sender, EventArgs e) {
// Stop the timer until execution is complete
timer1.Enabled = false;
try {
//Put all the executions here
...
}
finally {
// execution is complete (with or without exceptions), let's restart the timer
timer1.Enabled = true;
}
}
You could use an array to make it cleaner
private void timer1_Tick(object sender, EventArgs e)
{
var objBAL = new BAL();
Action[] functions = { objBAL.BL_Function1, objBAL.BL_Function2, objBAL.BL_Function3, objBAL.BL_Function3 };
foreach (var fun in functions)
{
var funCopy = fun;
try
{
funCopy ();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}

C# How to catch exception in a Task without block UI using wait

I have this code in a button click
private async void btnStart_Click(object sender, EventArgs e)
{
Msg.Clear();
stopWatch.Reset();
timer.Start();
stopWatch.Start();
lblTime.Text = stopWatch.Elapsed.TotalSeconds.ToString("#");
progressBar.MarqueeAnimationSpeed = 30;
try
{
await Task.Factory.StartNew(() =>
{
try
{
Reprocess();
}
catch (Exception ex)
{
Msg.Add(new clsMSG(ex.Message, "Error", DateTime.Now));
timer.Stop();
stopWatch.Stop();
throw;
}
});
}
catch
{
throw;
}
}
and this on the Reprocess method
private void Reprocess()
{
try
{
clsReprocess reprocess = new clsReprocess(tbBD.Text, dtpStart.Value, 50000);
reprocess.Start(reprocess.BD);
}
catch
{
throw;
}
}
when the Reprocess method fails, the Task goes to catch, but the throw fails (the throw inside catch (Exception ex)) and the UI blocks until the reprocess.Start method is completed.
I have two questions:
First: How can I catch the throw in the catch of my button?
Second: How can I prevent the UI blocks?
I hope you can understand me, sorry for my bad english.
You should not use Task.Factory.StartNew; Task.Run is both safer and shorter to write.
Also, you can only access UI controls from the UI thread. This may be the cause of the problems you're seeing, if Msg is data-bound to the UI. Even if it's not, you don't want to access unprotected collections (e.g., List<clsMSG>) from multiple threads.
Applying both of these guidelines reduces the code to:
private async void btnStart_Click(object sender, EventArgs e)
{
Msg.Clear();
stopWatch.Reset();
timer.Start();
stopWatch.Start();
lblTime.Text = stopWatch.Elapsed.TotalSeconds.ToString("#");
progressBar.MarqueeAnimationSpeed = 30;
try
{
await Task.Run(() => Reprocess());
}
catch (Exception ex)
{
Msg.Add(new clsMSG(ex.Message, "Error", DateTime.Now));
timer.Stop();
stopWatch.Stop();
throw;
}
}
If Reprocess throws an exception, that exception will be placed on the task returned from Task.Run. When your code awaits that task, that exception is re-raised and caught in the catch. At the end of the catch, the code will re-raise that exception (throw;).

How to stop the Parallel for loop process outside the loop?

I start the parallel for loop process from button click(Start Button). The parallel process going well but at the time I moved another page then I return to current parallel process page,process going well.
I try to stop the Parallel process from another button click(button stop). Is it possible?
protected void btnstart_Click(object sender, EventArgs e)
{
try
{
Parallel.For(0, dtrecord.Rows.Count, pOptions1, (j, pls) =>
{
if (Session["Stop"] != null)
{
pls.Stop();
Session.Remove("Stop2");
Session["ParallelStopped"] = 1;
}
else
{
Checkrecords(dtrecord, ImportFileID, j);
}
});
}
catch (Exception ex)
{
Log.Trace("Error occured in btnstop_Click");
Log.Error(ex.Message);
}
}
protected void btnstop_Click(object sender, EventArgs e)
{
try
{
Session["Stop"] = 1;
Session.Remove("start");
Session["start"] = null;
BindImportfileDetails();
BindImportrecordsdetails(hidimid.Value);
bindimportrecords();
Getrecordstatuscount();
Log.Trace("User has been stopping the import process");
}
catch (Exception ex)
{
Log.Trace("Error occured in btnstop_Click");
Log.Error(ex.Message);
}
}

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