应用程序启动时出现随机InvalidOperationException

时间:2012-11-21 14:45:52

标签: wpf startup appdomain

我在生产机器上不时地在应用程序启动时遇到问题。它不会在每次应用程序启动时发生,显然它只在重新启动时发生。该应用程序从登录启动,添加到HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Run。

显然,重置机器时问题比重启时更频繁。崩溃后手动启动应用程序成功。

启动期间抛出以下异常:

  

'System.Windows.Controls.TextBlock'的初始化引发了异常。   System.Windows.Markup.XamlParseException:'System.Windows.Controls.TextBlock'的初始化引发了异常。 ---> System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它。      在System.Windows.Threading.Dispatcher.VerifyAccess()      在System.Windows.Style.Seal()      在System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe,FrameworkContentElement fce,Style oldStyle,Style newStyle,Style& styleCache)      在System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)      在System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)      在System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)      在System.Windows.Controls.TextBlock.OnPropertyChanged(DependencyPropertyChangedEventArgs e)      在System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)      在System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex,DependencyProperty dp,PropertyMetadata metadata,EffectiveValueEntry oldEntry,EffectiveValueEntry& newEntry,Boolean coerceWithDeferredReference,Boolean coerceWithCurrentValue,OperationType operationType)      在System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp)      在System.Windows.FrameworkElement.UpdateStyleProperty()      在System.Windows.FrameworkElement.OnInitialized(EventArgs e)      在System.Windows.FrameworkElement.TryFireInitialized()      在System.Windows.FrameworkElement.EndInit()      在MS.Internal.Xaml.Runtime.ClrObjectRuntime.InitializationGuard(XamlType xamlType,Object obj,Boolean begin)      ---内部异常堆栈跟踪结束---      在System.Windows.Markup.XamlReader.RewrapException(例外e,IXamlLineInfo lineInfo,Uri baseUri)      在System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader,IXamlObjectWriterFactory writerFactory,Boolean skipJournaledProperties,Object rootObject,XamlObjectWriterSettings settings,Uri baseUri)      在System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader,Boolean skipJournaledProperties,Object rootObject,XamlAccessLevel accessLevel,Uri baseUri)      在System.Windows.Markup.XamlReader.LoadBaml(Stream stream,ParserContext parserContext,Object parent,Boolean closeStream)      在System.Windows.Application.LoadComponent(对象组件,Uri resourceLocator)      at Exception.Occurs.At.Different.Origins.Between.Startup()

从StackTrace中可以看出,在更新样式缓存时会发生一些事情。我无法在自己的计算机上重现这一点。启动应用程序时,此处不涉及任何线程,但有一些AppDomains。异常的起源并不总是相同,但它与Application.LoadComponent(对象组件,Uri resourceLocator)完全相同

因为我们的应用程序需要从不同于可执行文件(.. \ ProgramData ....)的位置查找配置文件,具体取决于操作系统,我们使用单独的AppDomain,我们在其中指示查找配置文件的位置因为我们找不到任何更好的解决方案来告诉ConfigurationManager在哪里查找文件。它当然可以与此相关,但不一定如此。编辑:ConfigurationManager.OpenMappedExeConfiguration似乎不起作用,因为它不会刷新通过Properties.Settings.Default等访问的任何用户或应用程序设置。

有没有人对如何处理此事有任何建议或建议?对不起,我无法为您提供重现的样本。

3 个答案:

答案 0 :(得分:1)

该异常是因为您正在从不是可视线程的线程修改可视元素。我知道这是因为在你的例外的第一行它说:

Initialization of 'System.Windows.Controls.TextBlock' threw an exception. System.Windows.Markup.XamlParseException: Initialization of 'System.Windows.Controls.TextBlock' threw an exception. ---> System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

所有其他例外无关紧要。我认为这是在你加载初始配置时,然后你使用其他线程。随机行为可能是有时在加载TextBlock控件之前找到配置,所以这次不会抛出异常。

要解决此问题,请查看this问题,以及我给出的最后一个答案(使用SynchronizationContext的答案,它真正适用于使用多个线程的WPF应用程序)。如果不清楚评论,我会在这里写出解决方案。

希望这个答案有助于发现随机错误,它是一种苛刻的......

答案 1 :(得分:0)

我不确定导致此异常的是什么,但我的解决方法有一个解决方法。

您可以使用ConfigurationManager.OpenMappedExeConfiguration而不是仅为加载其他配置文件创建单独的AppDomain,这样您就可以从本地文件系统的任何位置加载任何.config文件。

你这样使用它:

//Map the new configuration file.
var configFileMap = new ExeConfigurationFileMap() { ExeConfigFilename = @"c:\myOther.config"};

//Get the mapped configuration file
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);

使用config.GetSection()获取特定部分以供只读使用,或直接使用config对象在运行时更改配置。

并且您不需要不同的AppDomain,这将意味着更快的启动时间:)

答案 2 :(得分:0)

摆脱用于指定配置文件的额外AppDomain,并将其替换为this link中指定的方法,解决了这个问题。