locked
Exception handling RRS feed

  • Question

  • Hello,
    I am running a BackgroundWorker to upload files, I want to check the exceptions to see if the exception in the BackgroundWorker is an IOException it should show a messagebox and then carry on with the process. e.g if the file is opened by MS Word it should say that the file can not be uploaded , close the file and try again.
    how should I do this, I mean canceling the BackgroundWorker in the process itself. let me explain more
    I have a method doUploadFilesToServer which I run as a background process.

    public static void uploadFilesToServer(String[] filePaths, uploadFilesToServerDelegate doThis)
            {
                uploadFilesToServerDelegate_ = doThis;
    
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += doUploadFilesToServer; 
                bw.RunWorkerCompleted += uploadFilesToServerCompleted;
                bw.RunWorkerAsync(filePaths);
            }
    
           private static void doUploadFilesToServer(object sender, DoWorkEventArgs e)  //(String[] filePaths)
            {
                does some stuff
    
                    try
                    {
                      does some stuff
                    }
                    catch (Exception exc)
                    {                   
                        throw exc;
                    }
    
                 does some stuff
    how should I process the exc. I get errors when I try to do something like this:
    catch{
     if ( exc is IOEXception)
    {
      do something
    }
    else if ( exc is some other exception
    {
     
    }
    ...
    thank you

    es
    Wednesday, August 26, 2009 7:37 AM

Answers

  • hello
    yes you are right, sorry. I went up the call ladder! and put a try/catch on the method that was calling the background worker.

               try
                    {
                          ..... Some code that can not be shown .....
    } catch (System.Reflection.TargetInvocationException ex) { System.Windows.Forms.MessageBox.Show(ex.InnerException.InnerException.ToString()); return; }
    This did exactly what I wanted. It catches the inner exception(s), which  for me is the IOException shows which file can not be read and afterwards returns to the actual process. I am using two innerException so I can bypass  the unwanted text from upper methods before the actual IOException. I also made the mentioned method to throw an IOException.
                try
                    {
                       ... some code that reads files .... 
                    }
                    catch(IOException io)
                    {
                        throw new Exception(io.Message);
                    }
                    catch (Exception exc)
                    {
                        throw exc;
                    }
    It is not pretty, but is does the job. May be it would be better if I could change the output message afterwards.

    cheers,

    es
    • Marked as answer by ehsansad Wednesday, September 9, 2009 8:54 AM
    Wednesday, September 9, 2009 8:54 AM

All replies

  • I forgot to mention if I try to catch different exception I get an error on uploadResult

                 if (!uploadResult.Equals("OK"))
                        throw new Exception("Could not upload file to server!");
    

    Use of unsigned local variable uploadResult. I have also tried using different catch statments , but get the same error.



    es
    Wednesday, August 26, 2009 7:41 AM
  • To catch an IO Exception, you'd use the following pattern:

    try 
    {
       // dangerous stuff here. 
    } catch (IOException ex)
    {
       // the only things that will enter this block are IO Exceptions, 
       // anything else is going to get thrown.  You can handle the IO Exception
       // here and exit the background worker by simply adding a return statement
       // in this block.  
       MessageBox.Show("There is a problem reading the file.");
       return;
    } catch (Exception ex)
    {
       // any other kind of exception will arrive in this catch block. 
       // you can handle it smoothly, or throw it, depending on your
       // requirements. 
       throw ex;
    }

    // if we've gotten this far, everything is working smoothly. 

    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiTwitterLinkedInForumsBrowser
    • Proposed as answer by Ben Harnett Thursday, August 27, 2009 6:59 AM
    Wednesday, August 26, 2009 11:25 AM
  • Yes.  You'll need to do more work to report the error.  MessageBox.Show() won't always work properly, the message box can easily get hidden behind the currently active window, including your own.  Use Control.Invoke() to make sure it is shown on the UI thread.

    Hans Passant.
    Wednesday, August 26, 2009 11:50 AM
  • NoBugz,
    I recommend handling the ProgressChanged event and using the ReportProgress() method in the background worker.  Though it is designed for reporting progress from 0 - 100, it doesn't have to be so constrained (any value is okay, and a UserState object is allowed).

    The ReportProgress() will operate synchronously, and do all the work of switching to the correct thread.  The value of ReportProgress over Control.Invoke(), in this case, is that code is a little better decoupled.  I.e., the background worker does not need to reference an external control, nor does it even need to concern itself with UI thread and non-UI thread issues.  It simply implements a progress reporting protocol and lets the code that called it deal with it.

    With that in mind and lifting the code from the earlier reply...
    BackgroundWorkder bgWorker = sender as BackgroundWorker;
    try 
    {
       // dangerous stuff here. 
    } catch (IOException ex)
    {
       // the only things that will enter this block are IO Exceptions, 
       // anything else is going to get thrown.  You can handle the IO Exception
       // here and exit the background worker by simply adding a return statement
       // in this block.  
       bgWorker.ReportProgress(0,"There is a problem reading the file.");
       // and continue on...
    } catch (Exception ex)
    {
       // any other kind of exception will arrive in this catch block. 
       // you can handle it smoothly, or throw it, depending on your
       // requirements. 
       throw ex;
    }
    
    
    // if we've gotten this far, everything is working smoothly. 
    
    //and elsewhere...
    private void backgroundWorker1_ProgressChanged(int percent,
            ProgressChangedEventArgs e)
    {
        string msg = e.UserData as string;
        MessageBox.Show(String.Format("{0}",msg));
    }
    

    Les Potter, Xalnix Corporation, Yet Another C# Blog
    Wednesday, August 26, 2009 12:15 PM
  • Thanks, but is it possible to cancel the BackgroundWorker process all together and just show to GUI?
    Wednesday, August 26, 2009 12:17 PM
  • Thanks, but is it possible to cancel the BackgroundWorker process all together and just show to GUI?
    It is possible, but you have to set WorkerSupportsCancellation to true, then call the CancelAsync method from outside the BackgroundWorker.  After that, you'll have to periodically check the CancellationPending property from background thread, and if it's true, then return from the method.  

    In other words, there's no reason not to simply return from the method to cancel whenever an error arises.  You can set up a callback using RunWorkerCompleted, and then have a specific object that can return you the result of the entire call.  That would be a much better way to accomplish this task.  Simply "cancelling" the job in the middle without handling how you're going to cancel the job is probably not the best idea. 

    Also, Hans is absolutely correct.  I forgot to mention this.  If you call MessageBox.Show from the background thread, it's very possible your message box will show up in the background behind the main UI window.  This could make it inaccessible to the user.  I've detailed the Invoke/InvokeRequired pattern here for you to peruse. 

    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiTwitterLinkedInForumsBrowser
    Wednesday, August 26, 2009 12:28 PM
  • thank you.
    Wednesday, August 26, 2009 1:11 PM
  • The exception thrown in the BackgroundWorker is only available (stack trace and all) in the background worker.  If you are interested in any of that information, from the IOException or from the generic Exception, you must handle it (try/catch) in the background worker.  Otherwise, use a BeginInvoke type call with a Callback event handler.  In those calls that provide an IAsyncResult object, the EndInvoke() call will continue the exception chain to allow the callback handler to trap exceptions from the thread with try/catch.

    Agreed with David, cleanly exit the BackgroundWorker or any thread you might create.  Trap your thread errors and respond to them in the thread.  If you need to rethrow the exception, again, you may want to switch to a different thread mechanism.

    Les Potter, Xalnix Corporation, Yet Another C# Blog
    Wednesday, August 26, 2009 1:45 PM
  • Hi ehsansad,


    Like David said, we should handle IOException with a separate catch statement, if you want to notify the UI in background thread, I think both Nobugz and xalnix give the right suggestion. You can select either of them.  You can find a completed sample in MSDN document:

    http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

     

     

    For how to cancel current background thread, David has given the detailed explanation, here is a sample from codeproject:

    http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx

     

     

    If you have further question,  please feel free to  let me know.

     

    Have a good day.

    Guang-Ming Bian - MSFT

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help
    • Proposed as answer by Guang-Ming Bian - MSFT Monday, August 31, 2009 4:56 AM
    • Unproposed as answer by nobugz Monday, August 31, 2009 10:45 AM
    Thursday, August 27, 2009 6:53 AM
  • Hi ehsandsad,

    Did you solve the problem?



    Best regards,
    Guang-Ming Bian - MSFT
    Please remember to mark the replies as answers if they help and unmark them if they provide no help
    Tuesday, September 8, 2009 9:31 AM
  • Yes.
    Tuesday, September 8, 2009 9:56 AM
  • Hi ehsansad,

    If the solution is coming from above replies, I suggest you make it as answer, it will be helpful to other community member. It also encourage them to reply your thread next time.


    If you find the solution, could you show it in this thread, it will be also helpful to other community member.




    Best regards,
    Guang-Ming Bian - MSFT
    Please remember to mark the replies as answers if they help and unmark them if they provide no help
    Wednesday, September 9, 2009 7:37 AM
  • hello
    yes you are right, sorry. I went up the call ladder! and put a try/catch on the method that was calling the background worker.

               try
                    {
                          ..... Some code that can not be shown .....
    } catch (System.Reflection.TargetInvocationException ex) { System.Windows.Forms.MessageBox.Show(ex.InnerException.InnerException.ToString()); return; }
    This did exactly what I wanted. It catches the inner exception(s), which  for me is the IOException shows which file can not be read and afterwards returns to the actual process. I am using two innerException so I can bypass  the unwanted text from upper methods before the actual IOException. I also made the mentioned method to throw an IOException.
                try
                    {
                       ... some code that reads files .... 
                    }
                    catch(IOException io)
                    {
                        throw new Exception(io.Message);
                    }
                    catch (Exception exc)
                    {
                        throw exc;
                    }
    It is not pretty, but is does the job. May be it would be better if I could change the output message afterwards.

    cheers,

    es
    • Marked as answer by ehsansad Wednesday, September 9, 2009 8:54 AM
    Wednesday, September 9, 2009 8:54 AM