Feature layer crashing on query complete

2744
7
12-04-2013 03:58 AM
Labels (1)
JornWildt
New Contributor II
In my WPF application I have an ArcGIS map with a set of various feature layers. When I execute the program on my local developer machine it works fine. Unfortunately, once it is deployed on a customer machine, it crashes with the stack trace below.

What happens seems to be that one of the internal ArcGIS event handlers are executed from a background thread and tries to access/modify a graphics layer, which in turns touches WPF ... and then, bang, we get a "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.".

The stack trace doesn't have a single trace from my program - it all happens internally in the ArcGIS WPF components.

Can anyone help with an idea of what is going wrong?

[INDENT]
ERROR 2013-12-02 13:00:53,988 125226ms  [Main] App                    WriteLog           - Catching Unhandled exception
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
   at System.Windows.Threading.Dispatcher.VerifyAccess()
   at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
   at ESRI.ArcGIS.Client.GraphicsLayer.<Graphics_Collectionchange d>b__1(Graphic a)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ESRI.ArcGIS.Client.GraphicsLayer.Graphics_Collectionchange d(Object sender, NotifyCollectionchange dEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionchange d(NotifyCollectionchange dEventArgs e)
   at ESRI.ArcGIS.Client.GraphicCollection.AddRange(IEnumerable`1 items)
   at ESRI.ArcGIS.Client.FeatureLayer.task_QueryComplete(Object sender, QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.OnExecuteCompleted(QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.<>c__DisplayClassf.<ExecuteAsync>b__d(Task`1 result)
   at ESRI.ArcGIS.Client.Tasks.TaskBase.<>c__DisplayClassc`1.<HandeEventBasedTask>b__a(Task`1 result)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.TaskExceptionHolder.Finalize()
---> (Inner Exception #0) System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
   at System.Windows.Threading.Dispatcher.VerifyAccess()
   at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
   at ESRI.ArcGIS.Client.GraphicsLayer.<Graphics_Collectionchange d>b__1(Graphic a)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ESRI.ArcGIS.Client.GraphicsLayer.Graphics_Collectionchange d(Object sender, NotifyCollectionchange dEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionchange d(NotifyCollectionchange dEventArgs e)
   at ESRI.ArcGIS.Client.GraphicCollection.AddRange(IEnumerable`1 items)
   at ESRI.ArcGIS.Client.FeatureLayer.task_QueryComplete(Object sender, QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.OnExecuteCompleted(QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.<>c__DisplayClassf.<ExecuteAsync>b__d(Task`1 result)
   at ESRI.ArcGIS.Client.Tasks.TaskBase.<>c__DisplayClassc`1.<HandeEventBasedTask>b__a(Task`1 result)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()<---
[/INDENT]

Thanks, Jørn
0 Kudos
7 Replies
MichaelBranscomb
Esri Frequent Contributor
Hi,

Are you able to put together a small reproducer app which demonstrates the issue? (are the feature services publicly accessible / or the Map Packages shareable?)

Cheers

Mike
0 Kudos
JornWildt
New Contributor II
Sorry, but, no I have no small example or public service. Right now I am investigating whether its one machine which is bad or if it happens on all customer machines. I will get back if I find some pattern.
0 Kudos
JornWildt
New Contributor II
I have now removed my feature layers and then it works - but that's rather silly of course since I need the feature layers. But then I got to my own code which also handles QueryTasks complete - and now it fails there instead with the same kind of error.

The stack trace is slightly different but the exception is the same:

ERROR 2013-12-19 16:14:56,775 72613ms  [Main] App                    WriteLog           - Catching Unhandled exception
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
   at System.Windows.Threading.Dispatcher.VerifyAccess()
   at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
   at ESRI.ArcGIS.Client.Graphic.get_Layer()
   at ESRI.ArcGIS.Client.Graphic.set_Symbol(Symbol value)
   at CBrain.F2.ArcGIS.Client.UserControls.ArcGISMapViewer.QueryTask_ExecuteCompleted(Object sender, QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.OnExecuteCompleted(QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.<>c__DisplayClassf.<ExecuteAsync>b__d(Task`1 result)
   at ESRI.ArcGIS.Client.Tasks.TaskBase.<>c__DisplayClassc`1.<HandeEventBasedTask>b__a(Task`1 result)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.TaskExceptionHolder.Finalize()
---> (Inner Exception #0) System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
   at System.Windows.Threading.Dispatcher.VerifyAccess()
   at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
   at ESRI.ArcGIS.Client.Graphic.get_Layer()
   at ESRI.ArcGIS.Client.Graphic.set_Symbol(Symbol value)
   at CBrain.F2.ArcGIS.Client.UserControls.ArcGISMapViewer.QueryTask_ExecuteCompleted(Object sender, QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.OnExecuteCompleted(QueryEventArgs args)
   at ESRI.ArcGIS.Client.Tasks.QueryTask.<>c__DisplayClassf.<ExecuteAsync>b__d(Task`1 result)
   at ESRI.ArcGIS.Client.Tasks.TaskBase.<>c__DisplayClassc`1.<HandeEventBasedTask>b__a(Task`1 result)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()<---

The very strange part here is that the code called by OnExecuteCompleted runs on the main thread - both on my developer machine (where I can debug the program) as well as on the customer machine where I log the thread ID in "ArcGISMapViewer.QueryTask_ExecuteCompleted".

How on earth can I get "The calling thread cannot access this object because a different thread owns it." when accessing the WPF UI elements from the *main* thread? And only on the customer machine, not my own .... Heeeeelp ....

/Jørn
0 Kudos
RichardWatson
Frequent Contributor
I think that what you really want to know is which thread owns the object. 

That might be something like control.Dispatcher.Thread.

This link tells you how to check if your thread is the owner and how to dispatch the call to the correct thread:

http://stackoverflow.com/questions/9732709/the-calling-thread-cannot-access-this-object-because-a-di...
0 Kudos
JornWildt
New Contributor II
Thanks for the pointers, that has helped me a bit. I added some logging of the dispatcher threads. Something like this:

QueryTask queryTask = new QueryTask(url);
queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;

private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args)
{
  FeatureSet featureSet = args.FeatureSet;
  if (featureSet.Features.Count > 0)
  {
    // Add results to the map.
    foreach (Graphic resultFeature in featureSet.Features)
    {
      Logger.DebugFormat("LayoutRoot: Dispatcher.Thread: {0}, {1}", LayoutRoot.Dispatcher.Thread.ManagedThreadId, LayoutRoot.Dispatcher.Thread.Name);
      Logger.DebugFormat("resultFeature: Dispatcher.Thread: {0}, {1}", resultFeature.Dispatcher.Thread.ManagedThreadId, resultFeature.Dispatcher.Thread.Name);
      resultFeature.Symbol = LayoutRoot.Resources["FinalFillSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol;
      
      ... CRASH ...
    }
  }
}


From the log I can now see that LayoutRoot (an element in the current UserControl) has thread=1 whereas resultFeature (the ArcGIS QueryTask result) has thread=4.

That explains the crash ... but now I need to figure out how ArcGIS Runtime can create WPF UI features on the wrong thread.

Perhaps I am required to somehow copy these features to new features on the right thread? I don't think so - especially because ArcGIS own FeatureLayers crashes in the same way.

/Jørn
0 Kudos
JornWildt
New Contributor II
That piece of code is BTW a copy of the official sample code: http://help.arcgis.com/en/webapi/wpf/help/index.html#//01n70000001s000000
0 Kudos
JornWildt
New Contributor II
The observations above are based on ArcGIS runtime 10.2 from october 2013.

Now I tried to recompile with ArcGIS runtime 2.4.0.851 as downloaded from here: http://help.arcgis.com/en/webapi/wpf/
... AND IT WORKS!

So something has been introduced in 10.2 that makes QueryTask construct WPF UI elements on the wrong thread.