locked
Why do i get "InvalidOperationException" when using a backgroundworker ? RRS feed

  • Question

  • Hi all,

    Why do I have a "InvalidOperationException was hunhandled by user code.No process is associated with this object."
    when using this backroundworker :
    backgroundworker1
    with this following code.  The bug happens in the while loop below . It seems to be crashing with backgroundworker1.CancellationPendin in while statement according to debugging. The message when crashing is the one above.
            private void backgroundworker1_DoWork(object sender, DoWorkEventArgs e)
    {
    listProcesses = new List<System.Diagnostics.Process>();
    string directory = Path.GetDirectoryName(filepath);
    foreach (LinkAndPath linkAnPath in listLinks)
    {
    backgroundworker1.ReportProgress(10);
    stopWatch = Stopwatch.StartNew();
    actualUrl = Url;
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    launchApplication(linkAnPath.linkUrl, linkAnPath.path, process);
    while (!process.HasExited && !backgroundworker1.CancellationPending)
    {
    backgroundworker1.ReportProgress(10);
    Thread.Sleep(100);
    }
    if (backgroundworker1.CancellationPending)
    {
    e.Cancel = true;
    break;
    }
    stopWatch.Stop();
    backgroundworker1.ReportProgress(10);
    Utilities.writeToLogFile("INFO : DownloadSelectedLinksUI finish process for " + linkUrl);
    }
    }

    Furtheremore there is no compilation error in the code. I have changed manually some variable name to make it more simpler
    and readable.
    Monday, January 18, 2010 12:27 PM

Answers

  • Nothing is wrong with your link. I did not type correctly your link yesterday.  I had error 404.
    It works now.

    First of all i found a solution for my issue yesterday. In my loop, i was not waiting until the download was complete with webClient.
    It was causing issues.

    4.  Yes. When the loop is finished the download process stopped. Therefore the instance backgroundworker is killed.

    Finally i like your solution to go out of the loop properly. It is simple and clean.
    I will implement this now.

    The code which works last night:

     private void bgwDownloadSelectedLinks_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                listProcesses = new List<System.Diagnostics.Process>();
                string directory = Path.GetDirectoryName(contextDownload.filepath);
                foreach (LinkAndPath linkAnPath in contextDownload.listSelectedLinks)
                {
                    try
                    {
                        worker.ReportProgress(10);
                        #if (DEBUG)
                            stopWatch = Stopwatch.StartNew();
                        #endif
                        actualUrl = linkAnPath.linkUrl;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        if (linkAnPath.extensionUrl.Equals(Constants.MhtExtensionString))
                        {
                            launchApplication(linkAnPath.linkUrl, linkAnPath.path, process);
                            Utilities.writeToLogFile("INFO: DownloadSelectedLinksUI  start process for " + linkAnPath.linkUrl);
                            while ((!process.HasExited && !worker.CancellationPending))
                            {
                                waitDownloadFinish(worker);
                            }
                        }
                        else
                        {
                            WebClient webClient = new WebClient();
                            webClient.DownloadFile(linkAnPath.linkUrl, linkAnPath.path);
                            while ((webClient.IsBusy && !worker.CancellationPending))
                            {
                                waitDownloadFinish(worker);
                            }
                        }
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }
                        #if (DEBUG)
                            stopWatch.Stop();
                        #endif
                        worker.ReportProgress(10);
                        Utilities.writeToLogFile("INFO : DownloadSelectedLinksUI finish process for " + linkAnPath.linkUrl);
                     }
                     catch (Exception exception)
                     {
                         MessageBox.Show(Properties.Resources.MsgTheFollowingLinkNotDownloaded + linkAnPath.linkUrl, Constants.MsgDocosoftTitle,
                             MessageBoxButtons.OK, MessageBoxIcon.Error);
                         Utilities.writeToLogFile("ERROR : DownloadSelectedLinksUI failed to download " 
                             + linkAnPath.linkUrl + " with error " + exception.Message);
    
                     }
                }
            }


    Thanks guys for the help.
    • Marked as answer by Godeffroy Wednesday, January 27, 2010 7:34 AM
    Wednesday, January 27, 2010 7:34 AM

All replies

  • Could you post the call stack of this error?


    Tuesday, January 19, 2010 9:28 AM
  • Hi,

     

    Seems this error is always thrown when the process is not run.

     

    How is the issue now? If it still doesn’t work well, please tell us more details about this issue. This will make this issue more clearly.

     

    Look forward to your reply.

     

    Best regards,

    Ling Wang


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Friday, January 22, 2010 8:17 AM
  • Hi,

     

    How is the progress of issue now? If this has been resolved, it would be appreciated that if you have figured out the issue and share the solution here so that the answer can be found and used by other community members having the similar questions.

     

    J

     

    Best regards,

    Ling Wang


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Sunday, January 24, 2010 1:33 PM
  • I did not find a solution yet.
    Monday, January 25, 2010 7:28 AM
  •  

    -> Seems this error is always thrown when the process is not run.

    Have you checked this? Could you provide more information and then we can reproduce this issue?

     

    Best regards,

    Ling Wang


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Monday, January 25, 2010 8:35 AM
  • Thanks for the reply Ling Wang <abbr class="affil" /> and Zhi-Xin Ye

    Sorry for the late. I was not able to reply.
    As my first message said there is a message error saying "No process is associated with this object.".
    So I guess the error happens when the process is not run.

    The stacktrace is the following.
       at System.Diagnostics.Process.EnsureState(State state)
       at System.Diagnostics.Process.get_HasExited()
       at SaveSelectedLinks.DownloadSelectedLinksUI.bgwDownloadSelectedLinks_DoWork(Object sender, DoWorkEventArgs e)


    The new code is(contains a try catch block) :

            private void bgwDownloadSelectedLinks_DoWork(object sender, DoWorkEventArgs e)
            {
                listProcesses = new List<System.Diagnostics.Process>();
                string directory = Path.GetDirectoryName(contextDownload.filepath);
                foreach (LinkAndPath linkAnPath in contextDownload.listSelectedLinks)
                {
                    try
                    {
                        bgwDownloadSelectedLinks.ReportProgress(10);
                        stopWatch = Stopwatch.StartNew();
                        actualUrl = linkAnPath.linkUrl;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        if (linkAnPath.extensionUrl.Equals(Constants.MhtExtensionString))
                        {
                            launchApplication(linkAnPath.linkUrl, linkAnPath.path, process);
                            Utilities.writeToLogFile("INFO: DownloadSelectedLinksUI  start process for " + linkAnPath.linkUrl);
                        }
                        else
                        {
                            WebClient webClient = new WebClient();
                            webClient.DownloadFile(linkAnPath.linkUrl, linkAnPath.path);
                        }
                        while (!process.HasExited && !bgwDownloadSelectedLinks.CancellationPending)
                        {
                            bgwDownloadSelectedLinks.ReportProgress(10);
                            Thread.Sleep(100);
                        }
                        if (bgwDownloadSelectedLinks.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }
                        stopWatch.Stop();
                        bgwDownloadSelectedLinks.ReportProgress(10);
                        Utilities.writeToLogFile("INFO : DownloadSelectedLinksUI finish process for " + linkAnPath.linkUrl);
                     }
                     catch (Exception exception)
                     {
                         MessageBox.Show("error while downloading links with message =" + exception.Message, Constants.MsgDocosoftTitle,
                             MessageBoxButtons.OK, MessageBoxIcon.Error);
                     }
                }
            }
    Tuesday, January 26, 2010 2:47 PM
  • Hello,

    I don't know if this is impacting you or not, but I remember reading somewhere that you should not reference the instance variable from within the DoWork method. Instead, you should cast the sender.

    In your example above, instead of referencing backgroundworker1, reference CType(sender, BackGroundWorker).

    Good Luck!

    Tuesday, January 26, 2010 3:53 PM
  • Hi !

    Thans for the tip. Unfortunately it does not make a difference I replaced the reference backgrondworker1 with :

    BackgroundWorker worker = sender as BackgroundWorker;

    with the code :


            private void bgwDownloadSelectedLinks_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                listProcesses = new List<System.Diagnostics.Process>();
                string directory = Path.GetDirectoryName(contextDownload.filepath);
                foreach (LinkAndPath linkAnPath in contextDownload.listSelectedLinks)
                {
                    try
                    {
                        worker.ReportProgress(10);
                        stopWatch = Stopwatch.StartNew();
                        actualUrl = linkAnPath.linkUrl;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        if (linkAnPath.extensionUrl.Equals(Constants.MhtExtensionString))
                        {
                            launchApplication(linkAnPath.linkUrl, linkAnPath.path, process);
                            Utilities.writeToLogFile("INFO: DownloadSelectedLinksUI  start process for " + linkAnPath.linkUrl);
                        }
                        else
                        {
                            WebClient webClient = new WebClient();
                            webClient.DownloadFile(linkAnPath.linkUrl, linkAnPath.path);
                        }
                        while (!process.HasExited && !worker.CancellationPending)
                        {
                            worker.ReportProgress(10);
                            Thread.Sleep(100);
                        }
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }
                        stopWatch.Stop();
                        worker.ReportProgress(10);
                        Utilities.writeToLogFile("INFO : DownloadSelectedLinksUI finish process for " + linkAnPath.linkUrl);
                     }
                     catch (Exception exception)
                     {
                         MessageBox.Show("error while downloading links with message =" + exception.Message, Constants.MsgDocosoftTitle,
                             MessageBoxButtons.OK, MessageBoxIcon.Error);
                     }
                }
            }
    Thanks


    Tuesday, January 26, 2010 3:57 PM
  • Hello,

    I don't know if this is impacting you or not, but I remember reading somewhere that you should not reference the instance variable from within the DoWork method. Instead, you should cast the sender.

    In your example above, instead of referencing backgroundworker1, reference CType(sender, BackGroundWorker).

    Good Luck!



    Good tip, and on the right track.
    You need to observe some thread scope when it comes to referencing variables.
    Do not reference variables that are not declared within the scope of the methods being executed by the thread/worker.
    You reference several of what I assume to be class level variables.

    Be aware that some types like Timers and Stopwatch objects run on their own thread.
    I also have reservations about the way you call 'break' to jump out of the loop, which can leave garbage sitting on the call stack.
    I would use a For loop, instead of ForEach, and exit the loop by setting the loop index to maximum. 
    Let the loop exit normally.  How much time do you actually save by jumping out of it anyway?

    Finally, if you are trying to re-use the worker instance over and over.....don't. 
    Dispose of it in RunWorkerCompleted and get a new instance when you re-use it.

    Check out the following link for a sample form, including the issue with jumping out of a loop.
    Start/Pause the worker repeatedly to cause the issue.

    http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/52dcb460-90a3-45f2-ae23-bcb60514c542

    It has the same form in VB, C#, and C++.

    Rudy  =8^D

    Mark the best replies as answers. "Fooling computers since 1971."
    Tuesday, January 26, 2010 4:26 PM
  • Hi Rudedog2,

    Good points !
    First of all the link is incorrect at http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/52dcb460-90a3-45f2-ae23-bcb60514c542 .

    1. I need to get out of the loop because if a user clicks "Cancel" on the application form, all the processes need to be terminated.
    When the button Cancel is fired then it fired the code backgroundworker.CancelAsync().
    Therefore It will stop the thread background worker.

    2. I just removed Stopwatch object from my application but the issue is still there.

    3. "Do not reference variables that are not declared within the scope of the methods being executed by the thread/worker."
    Are you saying i should not call the following :

    listProcesses = new List<System.Diagnostics.Process>();
    ... some code
      stopWatch = Stopwatch.StartNew();
                        actualUrl = linkAnPath.linkUrl;
    Can you confirm this ?

    4. "Finally, if you are trying to re-use the worker instance over and over.....don't. 
    Dispose of it in RunWorkerCompleted and get a new instance when you re-use it."
    What do you mean by that ?
    bgwDownloadSelectedLinks_DoWork is only run once so the worker instance should be instanciated only once.


    Tuesday, January 26, 2010 5:13 PM
  • What is it that makes you say that is not the correct link?
    What were you expecting to see?
    That is the correct link.  I just tested it again.  The samples I referred to are there.

    BGWDemoForm1

    Try scrolling down to towards the bottom, that is where my samples are located.

    1.  My sample demonstrates how to Cancel a BGW.

    2.  You reference more than just a stopwatch object declared outside of the thread's scope.

    3.  Correct.  You should not be calling variables declared at the class level. 
         Pass references to them in the DoWorkEventArgs parameter, instead.
         The object that you pass on the overload of RunWorkerAsynch(object), will become e.Argument.

    4.  I was asking if you re-use the worker. 
         Your reply suggests that you perform only one download and close the UI thread.  Is that so?

    You may not have noticed what I consider to be the most important issue.  Calling "break" to jump out of the loop.

    Mark the best replies as answers. "Fooling computers since 1971."
    Tuesday, January 26, 2010 5:23 PM
  • Nothing is wrong with your link. I did not type correctly your link yesterday.  I had error 404.
    It works now.

    First of all i found a solution for my issue yesterday. In my loop, i was not waiting until the download was complete with webClient.
    It was causing issues.

    4.  Yes. When the loop is finished the download process stopped. Therefore the instance backgroundworker is killed.

    Finally i like your solution to go out of the loop properly. It is simple and clean.
    I will implement this now.

    The code which works last night:

     private void bgwDownloadSelectedLinks_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                listProcesses = new List<System.Diagnostics.Process>();
                string directory = Path.GetDirectoryName(contextDownload.filepath);
                foreach (LinkAndPath linkAnPath in contextDownload.listSelectedLinks)
                {
                    try
                    {
                        worker.ReportProgress(10);
                        #if (DEBUG)
                            stopWatch = Stopwatch.StartNew();
                        #endif
                        actualUrl = linkAnPath.linkUrl;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        if (linkAnPath.extensionUrl.Equals(Constants.MhtExtensionString))
                        {
                            launchApplication(linkAnPath.linkUrl, linkAnPath.path, process);
                            Utilities.writeToLogFile("INFO: DownloadSelectedLinksUI  start process for " + linkAnPath.linkUrl);
                            while ((!process.HasExited && !worker.CancellationPending))
                            {
                                waitDownloadFinish(worker);
                            }
                        }
                        else
                        {
                            WebClient webClient = new WebClient();
                            webClient.DownloadFile(linkAnPath.linkUrl, linkAnPath.path);
                            while ((webClient.IsBusy && !worker.CancellationPending))
                            {
                                waitDownloadFinish(worker);
                            }
                        }
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }
                        #if (DEBUG)
                            stopWatch.Stop();
                        #endif
                        worker.ReportProgress(10);
                        Utilities.writeToLogFile("INFO : DownloadSelectedLinksUI finish process for " + linkAnPath.linkUrl);
                     }
                     catch (Exception exception)
                     {
                         MessageBox.Show(Properties.Resources.MsgTheFollowingLinkNotDownloaded + linkAnPath.linkUrl, Constants.MsgDocosoftTitle,
                             MessageBoxButtons.OK, MessageBoxIcon.Error);
                         Utilities.writeToLogFile("ERROR : DownloadSelectedLinksUI failed to download " 
                             + linkAnPath.linkUrl + " with error " + exception.Message);
    
                     }
                }
            }


    Thanks guys for the help.
    • Marked as answer by Godeffroy Wednesday, January 27, 2010 7:34 AM
    Wednesday, January 27, 2010 7:34 AM
  • Hello,

    Thanks for posting your final solution. It's looking pretty good. A minor observation. Sorry that I don't remember the source, but I remember reading somewhere that you should only throw exceptions within back grounder worker thread code if you rethrow them. Then you can handle the exceptions within your RunWorkerCompleted event code, perhaps something like the pseudo code below. Good Luck!
        if (e.Cancel == true) { 
            MessageBox.Show("Cancellation Message"); 
        } 
        else if (e.Error != null) { 
            MessageBox.Show("Error Message"); 
        } 
        else { 
            // Finish Processing. 
        } 
    




    • Proposed as answer by Rudedog2 Wednesday, January 27, 2010 4:14 PM
    Wednesday, January 27, 2010 12:25 PM



  • BINGO!  J2 wins the jackpot.

    That's the ticket.  A BGW already runs inside of Try/Catch block when you call RunWorkerAsync.  Any errors are caught and are reported back to the main thread in the RunWorkerCompletedEventArgs parameter's Error property.  My sample uses nearly identical code.

    You will get into trouble calling for MessageBoxes on the worker thread. 
    All of that error handling should be done on the main thread.

    You will also eventually throw an exception by calling break to jump out of the ForEach loop like that.
    My code sample demonstrates this type of booby trap, too. 
    Modify my code at the indicated spot to "break" instead of setting the loop index to maximum.
    Setting the index to max, allows the loop to exit and clean up the stack.  Break leaves garbage behind.
    After making the modification, run the program and hit Start/Pause several times.  You eventually get gonged.

    Mark the best replies as answers. "Fooling computers since 1971."
    • Edited by Rudedog2 Wednesday, January 27, 2010 4:13 PM warning
    Wednesday, January 27, 2010 1:53 PM
  • Thanks for these comments. i will add these improvements in my code too.
    Thursday, January 28, 2010 8:54 AM