ThreadStart.BeginInvoke throws NotSupportedException on Compact framework - c#

I'm working with threads on a compact framework project and have code that looks something like below. When I try to step into StartThreads(), a NotSupportedException is thrown. This seems a bit wierd, why is the exception thrown on the line calling StartThreads() and not inside, and what is it that's not supported on CF? I think its ThreadStart.BeginInvoke but that's not where the exception is actually being thrown.
void SomeMethod()
{
this.StartThreads(); // <- NotSupportedException is thrown here, I can't step into this method with the debugger
}
void StartThreads()
{
ThreadStart threadStart = BeginDoStuff;
threadStart.BeginInvoke(EndDoStuff, null);
}

The BeginInvoke mechanism is not supported in CF, along with the ThreadPool.
The reason you don't see the Exception where you expect is due to the way this is implemented. I am not totally sure about the details but BeginInvoke is not a normal method (of the Delegate class) but something that is injected at runtime (just guessing that last part).
The error occurs when the JIT compiler gets to work on the StartThreads method.

delegate.BeginInvoke is not supported on the CF.
However the ThreadPool is supported. You can use the thread pool to achieve essentially the same behavior.
void SomeMethod()
{
this.StartThreads();
}
void StartThreads()
{
System.Threading.ThreadPool.QueueUserWorkItem(DoStuff);
}
if you want it to call a callback when finished I suggest you read up on the Asynchronous Programming Model

Related

Void MoveNext() in Null reference exception

I have a WebAPI which is having the following piece of code in which there is Null reference exception in the code written in try block which is getting logged using my logger.
But in the TargetSite of the Exception getting logged, I am receiving Void MoveNext() instead of the method name in which this code is written.
What could be the reason for the same??
public async Task<ResponseStatus> ProcessRCSCNotification(IList<RecurringSubscriptionModelV2> recurringSubscriptionList, string appCD)
{
foreach (var model in modelList)
{
// Some code
try
{
// Exception occurs here
}
catch (Exception ex)
{
// Logger is logging exception here
}
}
return null;
}
You have an async method with several awaits. The compiler transform this whole method into a state machine and your method ends up actually only calling this state machine.
This state machine class has the mentioned MoveNext() method that now contains all the work you actually wanted to do.
To analyze your NullReferenceException you should rather check the StackTrace property of the exception than the TargetSite.
The method is an async/await method.
This kind of method is rewritten to a state machine with a MoveNext method. That's why your stack trace will identify this method as the one throwing that exception.
.NET Core 2.0 or 2.1 have either built-in or an extra nuget package that will fix stack traces like this to mention the actual method instead of the generated one.
You can read more about this here: Age of Ascent: Stacktrace improvements in .NET Core 2.1.
It might not fixup the TargetSite however, and I don't think it will handle .NET Framework.

Why CLR re-throws ThreadAbortException?

I got the following code from book "Concurrent Programming on Windows" :
void Main()
{
try
{
try
{
Console.WriteLine("Inside Main Method");
Thread.CurrentThread.Abort();
}
catch(ThreadAbortException)
{
Console.WriteLine("Inside First Catch");
// Trying to swallow but CLR throws it again....
}
}
catch(ThreadAbortException)
{
Console.WriteLine("Inside Second Catch");
//Thread.ResetAbort();
}
}
I am interested in knowing as why CLR re-throws the ThreadAbortException ? And it keeps doing it until I call "Thread.ResetAbort()". Secondly, is there any other system defined exception, which gets special treatment from CLR ?
I am interested in knowing as why CLR re-throws the ThreadAbortException?
Because the thread is being aborted. People handle all exceptions all the time, even though doing so is dangerous. It would be bizarre if an error logging routine, say, kept a thread that was supposed to be destroyed alive forever, no?
is there any other system defined exception, which gets special treatment from CLR?
Yes, there are several. Out of stack and out of memory exceptions, for example, also have special behaviours.
It's a special exception, http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx, see remarks. From my understanding the reason this happens is that .Net is giving you the ability to do any clean up work before the thread closes.
See this for a bit about the plumbing: http://ondotnet.com/pub/a/dotnet/2003/02/18/threadabort.html

I can't catch exceptions in an Invoked delegate

I have a delegate which is attached to an event in the Excel interop component. The goal is to update a winforms control with updated info from Excel. Since I'm changing Control properties I need to use Invoke:
public delegate void DataGridViewUpdate(object[,] data);
...
excel.InteractiveEdit( delegate(object[,] data) {
Invoke(new Common.DataGridViewUpdate(back_from_excel), new object[] { data });
});
...
private void back_from_excel(object[,] data) {
// datagridview updating code
// an exception is thrown here !
}
(This code is in the Form class that I'm updating so it's Invoking on this)
Basically my problem is that when an exception occurs in the back_from_excel(object[,] data) method, the debugger doesn't catch it. I know the delegate is running in the correct UI thread because I have no problems manipulating form controls.
Specifically what happens is that when back_from_excel hits an unhandled exception, it stops executing at that point. The rest of the application continues running and is responsive. The debugger doesn't pause. The output pane shows:
A first chance exception of type 'System.NullReferenceException' occurred in My Application.exe
A first chance exception of type 'System.NullReferenceException' occurred in System.Windows.Forms.dll
It doesn't give me any hints about which line caused the problem, just that it's somewhere in the .exe.
My question is: am I doing the Invoke thing right? It seems kind of strange to have delegate - Invoke - delegate chained together like that, but I do need to pass a delegate that Invokes a delegate. Is my problem in Visual Studio rather than in C#? If so how do I get the debugger re-attached to that UI thread?
A "first chance exception" indicates that an exception was thrown, but that it was caught at some point. Since you're passing a delegate to the InteractiveEdit method, that method can easily swallow any exceptions produced by the delegate.
By default, Visual Studio will only catch exceptions that don't get caught. If you want to catch all exceptions, regardless of whether they are caught, you need to configure Visual Studio to break on all exceptions. See this link for details on how to do this.

How to check if Thread code runs in try-catch block

I would like to validate our code and check if every Thread that we execute runs in try catch block.
A valid sample:
Thread loadDataThread = new Thread(new ThreadStart(LoadData));
public void LoadData()
{
try {/*do something*/}
catch(Exception ex) { /*Handle exception*/ }
}
Not valid sample:
Thread loadDataThread = new Thread(new ThreadStart(LoadData));
public void LoadData()
{
/* do something */
}
Is this something that could be verified with FxCop or some other tool. The similar rule could be applied for some other things eg. Timer Ticks etc...
See http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/a257a910-126e-4c8d-aab3-3199347346ec for an example of how to detect a wrapping try/catch block in an FxCop rule. What's actually quite a bit trickier to do is detect which methods are susceptible to being run from a background thread since they're not all spawned using obvious launchers like Thread.Start or ThreadPool.QueueUserWorkItem.
That said, you might want to reconsider switching your approach from adding wrapping try/catches to using custom thread launchers that add the try/catch for you. (You could then create an FxCop rule to verify that the custom launchers/helpers are being used instead of the base framework analogs.) This would have the advantage of allowing you to systematically apply other changes to all thread (e.g.: setting cultures, tracking launching stack trace for use in later exception logging, etc.) without needing to change all the methods run from spawned threads.
I do not know if you can add a custom rule for this in FXCop, but you could use Mono.Cecil to do this, but it is not that simple.
This is a very good resource for rolling your own FxCop rule. You may find many other by googling for the same.
I believe that you can start looking at callers for Thread constructor. Then in calling statement, you can get address of thread procedure by looking at the delegate parameter. Once method ref is obtained, you need inspect statements within method body for the structure you are hoping for.
this does not answer your question directly but is probably pertinent.
Are you interested in doing the above because you do not want your application to exit/crash when a thread throws an uncaught Exception? If yes, then you can add the following to your app.config file in the configuration section:
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
disclaimer Doing the above is not recommended but may be used in a situation of last resort.
Warning: If you decide to use the above your application will not report any errors and go on executing as best it can. As a result you should have a handler that will at least log any uncaught exceptions via
void AppStartup()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//log error
}

InvokeRequired Exception Handling

I noticed a few strange behaviors in a Windows Forms scenario which involves threads and UI, so, naturally, this means making use of the InvokeRequired property. The situation: my application makes use of a thread to do some work and the thread sends an event into the UI. The UI displays a message based on an Internationalization system which consists of a dictionary with keys. The I18N system cannot find a key in the dictionary and crashes.
Notes: application is in Debug Mode and I have a try-catch over the entire "Application.Run();" back in Program.cs. However, that try-catch is not reached, as what I will discuss here is based on inner Exception handling, but I mentioned it just in case.
So now here comes the fun parts:
Why, for the life of me, does Visual Studio "censor" exception information from me? In the code below, you will see on the if (InvokeRequired) branch, a try-catch. I log the exception. ex.InnerException is NULL and the provided ex.StackTrace is anemic (only 1 step in it). Now if I comment the try-catch and simply let it crash via the Debugger, I get a much ampler stack trace. Why is that?
To make things worse, neither of the two stack traces versions contain any information about the i18N crash. They just say "The given key was not present in the dictionary." and give me a stack trace up to the Invoke declaration.
On the else branch (that is, InvokeRequired == false), if I put a try-catch, I can successfully catch my Exception back to the i18n system. As you can see, I tried to send my exception with InnerException back to the InvokeRequired == true branch. However, even so, InnerException stays NULL there and I cannot access my i18N error.
I am puzzled by all these things and maybe somebody can help shed some light over here. If you got really strong lanterns that is.
Here is the function's code.
private delegate void AddMessageToConsole_DELEGATE (frmMainPresenter.PresenterMessages message);
private void AddMessageToConsole (frmMainPresenter.PresenterMessages message)
{
if (InvokeRequired)
{ //Catching any errors that occur inside the invoked function.
try { Invoke(new AddMessageToConsole_DELEGATE(AddMessageToConsole), message); }
catch (Exception ex) { MSASession.ErrorLogger.Log(ex); }
//Invoke(new AddMessageToConsole_DELEGATE(AddMessageToConsole), message);
}
else
{
string message_text = ""; //Message that will be displayed in the Console / written in the Log.
try
{
message_text = I18N.GetTranslatedText(message)
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
txtConsole.AppendText(message_text);
}
}
Yes, this is built-in behavior for Control.Invoke(). It only marshals the deepest nested InnerException back to the caller. Not so sure why they did this, beyond avoiding reporting exceptions that were raised by the marshaling code and would confuzzle the reader. It was done explicitly, you cannot change the way it works.
But keep your eyes on the ball, the real problem is that the string indeed cannot be found in the dictionary. The reason for that is that your background thread runs with a different culture from your UI thread. Different cultures have different string comparison rules. You either need to give your dictionary a different comparator (StringComparer.InvariantCulture) or you should switch your background thread to the same culture as your UI thread.
Dealing with a non-system default culture in your UI thread can be difficult, all other threads will be started with the system default. Especially threadpool threads are troublesome, you don't always control how they get started. And culture is not part of the Thread.ExecutionContext so doesn't get forwarded. This can cause subtle bugs, like the one you ran into. Other nastiness is, say, SortedList which suddenly becomes unsorted when read by a thread that uses a different culture. Using the system default culture is strongly recommended. Its what your user is likely to use anyway.
The call stack problem is a known issue with Control.Invoke. You lose the call stack. Sorry. This is because it is rethrown on the UI thread using throw ex;.
The best solution would be to replace the background thread with a background Task. Note: this solution is only available for .NET 4.0. The Task class properly marshals exceptions. I wrote a blog entry about reporting progress from tasks, and the code in that blog entry will allow you to catch any UI update errors in the background thread, preserving the original exception and its call stack.
If you can't upgrade to .NET 4.0 yet, there is a workaround. Microsoft's Rx library includes a CoreEx.dll which has an extension method for Exception called PrepareForRethrow. This is supported in .NET 3.5 SP1 and .NET 4.0 (and SL 3 and SL 4). You'll need to wrap your UI updater method with something a little uglier:
private delegate void AddMessageToConsole_DELEGATE (frmMainPresenter.PresenterMessages message);
private void AddMessageToConsole (frmMainPresenter.PresenterMessages message)
{
if (InvokeRequired)
{
// Invoke the target method, capturing the exception.
Exception ex = null;
Invoke((MethodInvoker)() =>
{
try
{
AddMessageToConsole(message);
}
catch (Exception error)
{
ex = error;
}
});
// Handle error if it was thrown
if (ex != null)
{
MSASession.ErrorLogger.Log(ex);
// Rethrow, preserving exception stack
throw ex.PrepareForRethrow();
}
}
else
{
string message_text = ""; //Message that will be displayed in the Console / written in the Log.
try
{
message_text = I18N.GetTranslatedText(message)
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
txtConsole.AppendText(message_text);
}
}
Note: I recommend you start a migration away from ISynchronizeInvoke. It is an outdated interface that is not carried forward into newer UI frameworks (e.g., WPF, Silverlight). The replacement is SynchronizationContext, which supports WinForms, WPF, Silverlight, ASP.NET, etc. SynchronizationContext is much more suitable as an abstract "thread context" for a business layer.
Invoke on a Windows.Forms object causes the function to be invoked on a separate thread. If an Exception is thrown in your invoked function, the Exception is caught and a new TargetInvocationException is thrown.
This TargetInvocationException contains the initial Excpetion in it's InnerException property.
So, try to do it this way:
catch (TargetInvocationException ex) { MSASession.ErrorLogger.Log(ex.InnerException); }
Edit: Also, if you expand the InnerException property in the debugger, you will be able to access it's stacktrace, even if only as plain text.

Categories