Passing custom object to RunWorkerCompleted event in case of an exception - c#

My Console App uses System.ComponentModel.BackgroundWorker for threading purposes:
System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();
backgroundWorker.DoWork += (sender, e) =>
ReportStatus(worker, status, result, e);
backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker.RunWorkerAsync(worker);
As you can see that I am passing "worker" as an argument inside RunWorkerAsync.
What I am trying to achieve is that if there is an exception inside ReportStatus method I need the same "worker" object so that I can perform some operation (Call a service to notify that workers exception)
private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
try
{
proxy.ReportStatus(worker, status, result);
proxy.Close();
}
catch (Exception)
{
arg.Result = worker;
proxy.Abort();
throw;
}
}
In my exception block (I am not sure if this is the correct way!) I am assigning the worker to the Result so that I can get the same worker back when the RunWorkerCompleted method (backgroundWorker1_RunWorkerCompleted) is executed :
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
Worker worker = e.Result as Worker; // At this point I get an exception!
}
}

It's because you re-threw the exception. BackgroundWorker sees that as an exception unhandled by the DoWork handler and re-throws it back on the other thread when you get the Result value.
If you don't want it to do that, remove the throw in your catch in the DoWork handler.
if you passed the worker object into the BackgroundWorker, why don't use just use what you passed in in an exception handler wrapping the call to Result or in the block that tests Error? e.g.:
if (e.Error != null)
{
worker.DoSomething(); // no access of Result
}

.NET does NOT consider that Async Operation might have some result if an Error happened. That's why you will have pass it some other way.
I would recommend to implement custom exception class:
public class WorkerException:ApplicationException
{
public WorkerException(Worker worker,Exception innerException):base(null,innerException)
{ Worker = worker; }
public Worker Worker
{
get;
set;
}
}
And wrap you exception accordingly:
private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
try
{
proxy.ReportStatus(worker, status, result);
proxy.Close();
}
catch (Exception exception)
{
arg.Result = worker;
proxy.Abort();
throw new WorkerException(worker,exception);
}
}
In this case you will be able to retrieve Worker of exception, casting Error to WorkerException:
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error is WorkerException)
{
Worker worker = ((WorkerException)e.Error).Worker; // At this point I get an exception!
}
}

The RunWorkerCompletedEventArgs contains a UserState property which (I think) should be a reference to the same object that you passed to the RunWorkerAsync method. (It should also be in the DoWorkEventArgs as the Argument property.)
You'll need to experiment to confirm that this UserState is the right object (cast it as Worker) and that it is valid even when the DoWork handler threw an exception, but I think that could be what you're looking for.

Related

A single thread to which you can subscribe methods, to be executed in an unordered fashion

I need the following logic implemented:
a thread to which you can subscribe/unsubscribe methods at runtime.
It's fine for all these methods to have an header such as (Object sender, EventArgs e) and to return void.
These methods scope must be the scope of the class where they are defined lexically.
There's no guarantee about the order of execution
I've come up with the following implementation, which seems to do exactly what I need: basically I start an internal thread which triggers an event each x milliseconds. You can subscribe/unsubscribe delegates to this event through appropriate methods.
Before sticking to it I'd like to know if there may be subtle issues following this approach.
public class Orchestrator
{
private Thread _mainThread;
private event MethodDelegate _mainEvent;
public delegate void MethodDelegate (Object sender, EventArgs e);
private bool _stop = false;
private short _ms = 100;
public short PollingInterval { get { return _ms; }
set
{
_ms = value;
}
}
public Orchestrator()
{
_mainThread = new Thread(new ThreadStart(_execute));
}
public void Start()
{
_stop = false;
_mainThread.Start();
}
public void Stop()
{
_stop = true;
}
public void Clear()
{
_mainEvent = null;
}
public void Push(MethodDelegate method)
{
_mainEvent += method;
}
public void Pop(MethodDelegate method)
{
_mainEvent -= method;
}
private void _execute()
{
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
}
}
That's basically fine. You need to make _stop volatile. In C# the event accessor methods are thread-safe so that works fine.
The exception handling is very questionable. Do you really want to spam errors to the console? Define an event OnError and report errors to the consumer of your class.
You could use a timer or await Task.Delay to save a thread. This would make sense if there are a lot of such class instances at the same time. If there is just one this is likely not worth the effort.
You have a race condition which could cause a NullReferenceException, in:
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
Some other thread could unsubscribe from the event or call Clear() inbetween if (_mainEvent != null) and the call of _mainEvent.
To avoid this, you should copy _mainEvent into a local variable and check that against null, and use that instead:
var mainEvent = _mainEvent;
if (mainEvent != null)
try
{
mainEvent(this, new EventArgs());
In any case, I think you should be using a Timer for this rather than rolling-your-own.

ServiceControler.GetServices() silently bailing in a background thread

I am running the following line to get a list of all services for a given computer:
ServiceController[] services = ServiceController.GetServices(compName);
If I run this on the main thread and pass in a computer name that exists but I don't have permissions to view the services for, such as:
ServiceController.GetServices("OtherComp");
InvalidOperationException:
Cannot open Service Control Manager on computer 'OtherComp'. This operation might require other privileges.
I fully expect this to happen. However my issue comes with running this on a background thread. Take this fully complete console program:
using System.ComponentModel;
using System.ServiceProcess;
namespace ServiceTesting
{
internal class Program
{
private static void Main(string[] args)
{
ServiceAccessor sa = new ServiceAccessor();
sa.Run();
}
}
public class ServiceAccessor
{
BackgroundWorker bw;
public ServiceAccessor()
{
bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
public void Run()
{
bw.RunWorkerAsync();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
//this line is where the bail happens
var services = ServiceController.GetServices("OtherComputer");
}
void bw_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
// the code will never get to this method
if (e.Error != null)
{
//something
}
}
}
}
I would expect an exception to be thrown, but as soon as the code tries to execute this line, it bails out of the thread.
I can't wrap the line in a try\catch; it will won't catch it. This might be simmilar to ThreadAbort problems with asp.net (but that is just a guess).
The msdn page on the ServiceController Class says that the static function is thread safe, however, a commenter on the function's msdn page says that it is not.
Exception was catched by BackgroundWorker internally, you can view it via RunWorkerCompleted event:
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
// deal with error
}
}
http://msdn.microsoft.com/en-us/library/system.componentmodel.runworkercompletedeventargs.aspx
UPD: However, it works as expected with Thread class:
new Thread(() =>
{
try
{
var services = ServiceController.GetServices("OtherComputer");
}
catch
{
}
}).Start();

Thread that talk with UI?

I have this code:
private void buttonStart_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => GeneraListaCartelle())
.ContinueWith(t => GeneraListaCartelleCompletata()
, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
private void GeneraListaCartelle()
{
try
{
... some operation ....
}
catch (Exception err)
{
txtErrors.AppendText(err.Message);
}
}
GeneraListaCartelleCompletata()
{
... process finished...
}
and txtErrors is in the "main" thread (the UI). When I catch an error, the asynch thread cannot write to the UI control, and I get an invalid cross-thread exception.
Can I dialogate with the UI inside a Thread?
If you are using WinForms, you will need to Invoke your method on the UI-thread like
catch (Exception err)
{
if(this.InvokeRequired){
Action<Exception> act = ((ex) => {
txtErrors.AppendText(ex.Message);
});
this.Invoke(act, new object[] { err });
}
else{
txtErrors.AppendText(err.Message);
}
}
If you are using WPF you will need to
catch (Exception err)
{
if(this.Dispatcher.CheckAccess()){
txtErrors.AppendText(err.Message);
}
else {
Action<Exception> act = ((ex) => {
txtErrors.AppendText(ex.Message);
});
this.Dispatcher.Invoke(act, new object[] { err });
}
}
if You are targetting WinForm Application then:
try
{
... some operation ....
}
catch (Exception err)
{
if (txtErrors.InvokeRequired)
{
txtErrors.BeginInvoke(new MethodInvoker(
delegate { txtErrors.AppendText(err.Message); })
);
}
}
There's an example from msdn:
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);
// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control.
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
set CheckForIllegalCrossThreadCalls to false in the called form_load event handler
Pulled this out of an old project where I had to deal with updating the UI from another thread. Should work for you as well.
delegate void addtoValProg();
addtoValProg myDelegate;
myDelegate = new addtoValProg(invokeControl);
private void GeneraListaCartelle()
{
try
{
//... some operation ....
}
catch (Exception err)
{
invokeControl();
}
}
private void invokeControl()
{
if (this.InvokeRequired)
{
this.Invoke(this.myDelegate);
}
else
{
txtErrors.AppendText(err.Message);
txtErrors.Update();
}
}

Exception handler not being invoked

Running the really simple program below I'd expect 'FILTER REACHED' to execute when I click button1, but it doesn't get hit (neither with nor without debugger attached). Any ideas ... ?
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Dispatcher.CurrentDispatcher.UnhandledExceptionFilter += Dispatcher_UnhandledExceptionFilter;
doer();
}).Start();
}
void Dispatcher_UnhandledExceptionFilter(
object sender,
DispatcherUnhandledExceptionFilterEventArgs e)
{
MessageBox.Show("FILTER REACHED");
}
private void doer()
{
throw new NotImplementedException();
}
}
Thanks
According to the documentation on Dispatcher (found here) it looks like the filter function will only be used if an uncaught exception is raised from the Invoke or BeginInvoke methods on the Dispatcher.
So what happens if you replace doer() with Dispatcher.CurrentDispatcher.Invoke(doer) (or similar) instead?
You are calling the method (doer) from a thread which is not the dispatcher thread.. you have to invoke the method using Dispatcher in order to catch the exception for filtering.
new Thread(() =>
{
Dispatcher.CurrentDispatcher.UnhandledExceptionFilter += Dispatcher_UnhandledExceptionFilter;
Dispatcher.Invoke(new Action(()=>doer()));
}).Start();
try below code
new Thread(() =>
{
Dispatcher.CurrentDispatcher.UnhandledExceptionFilter += Dispatcher_UnhandledExceptionFilter;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(delegate
{
doer();
}));
}).Start();
Have you tried using AppDomain.UnhandledException instead?

How do I make event callbacks into my win forms thread safe?

When you subscribe to an event on an object from within a form, you are essentially handing over control of your callback method to the event source. You have no idea whether that event source will choose to trigger the event on a different thread.
The problem is that when the callback is invoked, you cannot assume that you can make update controls on your form because sometimes those controls will throw an exception if the event callback was called on a thread different than the thread the form was run on.
To simplify Simon's code a bit, you could use the built in generic Action delegate. It saves peppering your code with a bunch of delegate types you don't really need. Also, in .NET 3.5 they added a params parameter to the Invoke method so you don't have to define a temporary array.
void SomethingHappened(object sender, EventArgs ea)
{
if (InvokeRequired)
{
Invoke(new Action<object, EventArgs>(SomethingHappened), sender, ea);
return;
}
textBox1.Text = "Something happened";
}
Here are the salient points:
You can't make UI control calls from a different thread than the one they were created on (the form's thread).
Delegate invocations (ie, event hooks) are triggered on the same thread as the object that is firing the event.
So, if you have a separate "engine" thread doing some work and have some UI watching for state changes which can be reflected in the UI (such as a progress bar or whatever), you have a problem. The engine fire's an object changed event which has been hooked by the Form. But the callback delegate that the Form registered with the engine gets called on the engine's thread… not on the Form's thread. And so you can't update any controls from that callback. Doh!
BeginInvoke comes to the rescue. Just use this simple coding model in all your callback methods and you can be sure that things are going to be okay:
private delegate void EventArgsDelegate(object sender, EventArgs ea);
void SomethingHappened(object sender, EventArgs ea)
{
//
// Make sure this callback is on the correct thread
//
if (this.InvokeRequired)
{
this.Invoke(new EventArgsDelegate(SomethingHappened), new object[] { sender, ea });
return;
}
//
// Do something with the event such as update a control
//
textBox1.Text = "Something happened";
}
It's quite simple really.
Use InvokeRequired to find out if this callback happened on the correct thread.
If not, then reinvoke the callback on the correct thread with the same parameters. You can reinvoke a method by using the Invoke (blocking) or BeginInvoke (non-blocking) methods.
The next time the function is called, InvokeRequired returns false because we are now on the correct thread and everybody is happy.
This is a very compact way of addressing this problem and making your Forms safe from multi-threaded event callbacks.
I use anonymous methods a lot in this scenario:
void SomethingHappened(object sender, EventArgs ea)
{
MethodInvoker del = delegate{ textBox1.Text = "Something happened"; };
InvokeRequired ? Invoke( del ) : del();
}
I'm a bit late to this topic, but you might want to take a look at the Event-Based Asynchronous Pattern. When implemented properly, it guarantees that events are always raised from the UI thread.
Here's a brief example that only allows one concurrent invocation; supporting multiple invocations/events requires a little bit more plumbing.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class MainForm : Form
{
private TypeWithAsync _type;
[STAThread()]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
public MainForm()
{
_type = new TypeWithAsync();
_type.DoSomethingCompleted += DoSomethingCompleted;
var panel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
var btn = new Button() { Text = "Synchronous" };
btn.Click += SyncClick;
panel.Controls.Add(btn);
btn = new Button { Text = "Asynchronous" };
btn.Click += AsyncClick;
panel.Controls.Add(btn);
Controls.Add(panel);
}
private void SyncClick(object sender, EventArgs e)
{
int value = _type.DoSomething();
MessageBox.Show(string.Format("DoSomething() returned {0}.", value));
}
private void AsyncClick(object sender, EventArgs e)
{
_type.DoSomethingAsync();
}
private void DoSomethingCompleted(object sender, DoSomethingCompletedEventArgs e)
{
MessageBox.Show(string.Format("DoSomethingAsync() returned {0}.", e.Value));
}
}
class TypeWithAsync
{
private AsyncOperation _operation;
// synchronous version of method
public int DoSomething()
{
Thread.Sleep(5000);
return 27;
}
// async version of method
public void DoSomethingAsync()
{
if (_operation != null)
{
throw new InvalidOperationException("An async operation is already running.");
}
_operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(DoSomethingAsyncCore);
}
// wrapper used by async method to call sync version of method, matches WaitCallback so it
// can be queued by the thread pool
private void DoSomethingAsyncCore(object state)
{
int returnValue = DoSomething();
var e = new DoSomethingCompletedEventArgs(returnValue);
_operation.PostOperationCompleted(RaiseDoSomethingCompleted, e);
}
// wrapper used so async method can raise the event; matches SendOrPostCallback
private void RaiseDoSomethingCompleted(object args)
{
OnDoSomethingCompleted((DoSomethingCompletedEventArgs)args);
}
private void OnDoSomethingCompleted(DoSomethingCompletedEventArgs e)
{
var handler = DoSomethingCompleted;
if (handler != null) { handler(this, e); }
}
public EventHandler<DoSomethingCompletedEventArgs> DoSomethingCompleted;
}
public class DoSomethingCompletedEventArgs : EventArgs
{
private int _value;
public DoSomethingCompletedEventArgs(int value)
: base()
{
_value = value;
}
public int Value
{
get { return _value; }
}
}
}
As the lazy programmer, I have a very lazy method of doing this.
What I do is simply this.
private void DoInvoke(MethodInvoker del) {
if (InvokeRequired) {
Invoke(del);
} else {
del();
}
}
//example of how to call it
private void tUpdateLabel(ToolStripStatusLabel lbl, String val) {
DoInvoke(delegate { lbl.Text = val; });
}
You could inline the DoInvoke inside your function or hide it within separate function to do the dirty work for you.
Just keep in mind you can pass functions directly into the DoInvoke method.
private void directPass() {
DoInvoke(this.directInvoke);
}
private void directInvoke() {
textLabel.Text = "Directly passed.";
}
In many simple cases, you can use the MethodInvoker delegate and avoid the need to create your own delegate type.

Categories