Share via


BackgroundWorker does not fire the RunWorkerCompleted event

Question

Tuesday, October 4, 2016 7:44 AM

 I have windows service  and service starts multiple (20 approx) BackgroundWorker. Dowork event of each worker is calling methods of different class. it was working fine and RunWorkerCompleted event was getting invoked.

I have done some changes in one of the class which method is getting called from BackgroundWorker Do work event. In this class i am creating PDFs from SSRS using ReportViwer and PDFs are further used for email, printing or FAX with the help of WinFax. I have window handle and User objects are not getting cleared and reaching max limit. I have implemented Dispose for report viewer object and moved some of the object creation within loop to global to the class. Now my window handle issue got resolved, but RunWorkerCompleted event is not getting called.

Regards

Santosh 

All replies (3)

Wednesday, October 5, 2016 12:08 PM ✅Answered

Hi SantoshkDixit,

Thank you for posting here.

For your question, i could not test your code. Maybe there is something wrong with BackgroundWorker.RunWorkerCompleted Event.

**>>Now my window handle issue got resolved, but RunWorkerCompleted event is not getting called.

BackgroundWorker.RunWorkerCompleted Event is raised when the DoWork event handler returns.

If the operation completes successfully and its result is assigned in the DoWork event handler, you can access the result through theRunWorkerCompletedEventArgs.Result property.

The Error property of System.ComponentModel.RunWorkerCompletedEventArgs indicates that an exception was thrown by the operation.

The Cancelled property of System.ComponentModel.RunWorkerCompletedEventArgs indicates whether a cancellation request was processed by the background operation. If your code in the DoWork event handler detects a cancellation request by checking the CancellationPending flag and setting the Cancel flag of System.ComponentModel.DoWorkEventArgs to true, the Cancelled flag ofSystem.ComponentModel.RunWorkerCompletedEventArgs also will be set to true.

Here is a simple example for the BackgroundWorker.RunWorkerCompleted Event in MSDN article.

// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(
    object sender, RunWorkerCompletedEventArgs e)
{
    // First, handle the case where an exception was thrown.
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
    }
    else if (e.Cancelled)
    {
        // Next, handle the case where the user canceled 
        // the operation.
        // Note that due to a race condition in 
        // the DoWork event handler, the Cancelled
        // flag may not have been set, even though
        // CancelAsync was called.
        resultLabel.Text = "Canceled";
    }
    else
    {
        // Finally, handle the case where the operation 
        // succeeded.
        resultLabel.Text = e.Result.ToString();
    }

    // Enable the UpDown control.
    this.numericUpDown1.Enabled = true;

    // Enable the Start button.
    startAsyncButton.Enabled = true;

    // Disable the Cancel button.
    cancelAsyncButton.Enabled = false;
}

I hope this would be helpful to you.

If you have something else, please feel free to contact us.

Best Regards,

Wendy 

We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
Click HERE to participate the survey.


Wednesday, October 5, 2016 2:07 PM ✅Answered

Windows Services are not suiteable for Interactive GUI's. They lack the Interactive sessions for that. And BackgroundWorker is basically designed for Multithreading with GUI's.
As a result it can be insanely hard to even debug a service in the first place. How do you know the event is not being invoked?

If you need around 20 BackgroundWorkers, I can already tell you taht using BackgroundWorker is propably a bad idea. It is designed for Beginner cases. For 20 Threads, you should be using the Thread class or any other way of doing asynch programming.
I also have to wonder what you even need 20 BGW's for to begin with. 3-6 is a pretty high number already. 20 should be very rare.
What opeartion do you have, that you think such massive Paralellisation is nessesary?

A whole lot of things is not adding up in what you described.

Remember to mark helpfull answers as helpfull and close threads by marking answers.


Wednesday, October 5, 2016 2:43 PM ✅Answered

"I have done some changes in one of the class which method is getting called from BackgroundWorker Do work event"

Post the relevant code. There is no way for us to identify issues in your code if we cannot see the code. I suspect that you accidentally missed assigning an event handler to the complete event. Then again, if you're leaking resources then once you run out nothing will work. If you are leaking resources it is possible it is because your worker thread is never completing.

"moved some of the object creation within loop to global to the class"

That doesn't solve memory issues if this is a service. The service runs indefinitely. If you could post the code that is leaking we can probably show you what you're doing wrong.

" and service starts multiple (20 approx) BackgroundWorker. "

There probably isn't a good reason to be using a BWC in a service. With the advent of async/await you can simply use that instead. It solves the sync context issue that BWC was designed to solve initially. Since you're in a service the context shouldn't matter because you wouldn't have a UI. But you mentioned that you're using Winfax which may be a COM object that requires at least a hidden window. async/await can handle that situation provided you do the fax stuff on the main context.

"In this class i am creating PDFs from SSRS using ReportViwer and PDFs"

You don't need ReportViewer to generate a PDF from SSRS. SSRS has a simple URL interface that allows you to render any report in any supported format without the need for ReportViewer. RV is a UI component so if you don't have a UI you don't need RV.

Here's some sample code for how you can do that using the underlying web service. I prefer to use the web service because you can control the credentials being used. URL access is limited in this regard.

//We use strongly typed Report objects to enforce parameter
//requirements and keep the underlying code clean
//Ultimately they generate this generic context type
public class RenderReportContext
{
   public string Url { get; set; }
   public ICredentials Credentials { get; set; }
   public string ReportPath {get; set; }
   public string Format {get; set; }
   public List<ParameterValue> Parameters {get; set; }
}

private byte[] GenerateReportCore(RenderReportContext context)
        {
            string extension;
            string mimeType;
            string encoding;
            byte[] numArray;
            using (ReportExecutionService rs = new ReportExecutionService())
            {
                rs.Url = context.Url;
                rs.Credentials = context.Credentials;
                Warning[] warnings = null;
                string[] streamIds = null;
                rs.LoadReport(context.ReportPath, null);
                rs.SetExecutionParameters(context.Parameters.ToArray(), "en-us");
                numArray = rs.Render(format, "<DeviceInfo></DeviceInfo>", out extension, out encoding, out mimeType, out warnings, out streamIds);
            }
            return numArray;
        }

Michael Taylor
http://www.michaeltaylorp3.net