我将从问题摘要开始,然后我将详细介绍我到目前为止所得到的内容.
概述
在我的开发工作站中,我有Windows 8和Visual Studio 2012.我正在使用Caliburn和Autofac,如this post所述(基本上是this的简化版本).
当我在我的开发机器中构建并运行应用程序时,一切都按预期进行.但是,当我获取二进制文件并在Windows 7 / XP机器中执行它时,我得到以下错误,带有长堆栈跟踪:
system.invalidOperationException: IoC is not initialized
我可以在环境(除OS之外)看到的唯一区别是我的开发工作站有.NET 4.5,而Win7 / XP有.NET 4.0.
细节
Shellviewmodel只是一个空导体< Screen>. ShellView只有一个TextBlock.
App.xaml遵循Caliburn的推荐:
<Application x:Class="WpfApplication2.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication2"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary> <local:Bootstrapper x:Key="bootstrapper" /> </ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
public partial class App : Application { public App () { // hook on error before app really starts AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); try { this.InitializeComponent(); } catch (Exception e) { MessageBox.Show(e.ToString()); throw; } } public static void CurrentDomain_UnhandledException(object sender,UnhandledExceptionEventArgs e) { MessageBox.Show(((Exception)e.ExceptionObject).ToString()); } }
有趣的部分是Bootstrapper.如上所述,我有一个应用程序,并与Caliburn和Autofac一起运行,与一个类似于此处描述的Bootstrapper一起工作.例如,我创建了一个简化版本:
public class Bootstrapper : Bootstrapper<Shellviewmodel> { private IContainer container; protected IContainer Container { get { return this.container; } } protected override object GetInstance(Type serviceType,string key) { if (string.IsNullOrWhiteSpace(key)) { if (container.IsRegistered(serviceType)) return container.Resolve(serviceType); } else { if (container.IsRegisteredWithName(key,serviceType)) container.ResolveNamed(key,serviceType); } throw new Exception(string.Format("Could not locate any instances of contract {0}.",key ?? serviceType.Name)); } protected override IEnumerable<object> GetAllInstances(Type serviceType) { return this.Container.Resolve(typeof(IEnumerable<>).MakeGenericType(serviceType)) as IEnumerable<object>; } protected override void BuildUp(object instance) { this.Container.InjectProperties(instance); } protected override void Configure() { var builder = new ContainerBuilder(); builder.RegisterType<Shellviewmodel>(); builder.RegisterassemblyTypes(this.GetType().Assembly); builder.RegisterType<WindowManager>() .As<IWindowManager>() .SingleInstance(); builder.RegisterType<EventAggregator>() .As<IEventAggregator>() .SingleInstance(); this.container = builder.Build(); } }
在我的工作站中,它运行得很好:
我在Bootstrapper的GetInstance方法中加入了一些断点,它们被正确命中.
然后,我拿了二进制文件(bin / Debug)并尝试在Windows XP / 7虚拟机中运行它们.该应用程序无法启动,我得到以下异常:
system.invalidOperationException: IoC is not initialized. at Caliburn.Micro.IoC.<.cctor>b__0(Type service,String key) in c:\Users\Rob\Documents\CodePlex\caliburnmicro\src\Caliburn.Micro.Silverlight\IoC.cs:line 13 at Caliburn.Micro.IoC.Get[T](String key) in c:\Users\Rob\Documents\CodePlex\caliburnmicro\src\Caliburn.Micro.Silverlight\IoC.cs:line 32 at Caliburn.Micro.BootstrapperBase.displayRootViewFor(Type viewmodelType,IDictionary`2 settings) in c:\Users\Rob\Documents\CodePlex\caliburnmicro\src\Caliburn.Micro.Silverlight\Bootstrapper.cs:line 254 at Caliburn.Micro.BootstrapperBase.displayRootViewFor[Tviewmodel](IDictionary`2 settings) in c:\Users\Rob\Documents\CodePlex\caliburnmicro\src\Caliburn.Micro.Silverlight\Bootstrapper.cs:line 264 at Caliburn.Micro.Bootstrapper`1.OnStartup(Object sender,StartupEventArgs e) in c:\Users\Rob\Documents\CodePlex\caliburnmicro\src\Caliburn.Micro.Silverlight\Bootstrapper.cs:line 288 at System.Windows.Application.OnStartup(StartupEventArgs e) at System.Windows.Application.<.ctor>b__1(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback,Object args,Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source,Delegate method,Int32 numArgs,Delegate catchHandler) at System.Windows.Threading.dispatcherOperation.InvokeImpl() at System.Windows.Threading.dispatcherOperation.InvokeInSecurityContext(Object state) at System.Threading.ExecutionContext.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code,CleanupCode backoutCode,Object userData) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback callback,Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,Object state,Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,Object state) at System.Windows.Threading.dispatcherOperation.Invoke() at System.Windows.Threading.dispatcher.ProcessQueue() at System.Windows.Threading.dispatcher.WndProcHook(IntPtr hwnd,Int32 msg,IntPtr wParam,IntPtr lParam,Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd,Boolean& handled) at MS.Win32.HwndSubclass.dispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback,Delegate catchHandler) at System.Windows.Threading.dispatcher.InvokeImpl(dispatcherPriority priority,TimeSpan timeout,Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd,IntPtr lParam) at MS.Win32.UnsafeNativeMethods.MessageBox(HandleRef hWnd,String text,String caption,Int32 type) at System.Windows.MessageBox.ShowCore(IntPtr owner,String messageBoxText,MessageBoxButton button,MessageBoxImage icon,MessageBoxResult defaultResult,MessageBoxOptions options) at System.Windows.MessageBox.Show(String messageBoxText) at WpfApplication2.App..ctor() in c:\Users\Public\Projetos\Outros\WpfApplication3\WpfApplication2\App.xaml.cs:line 27 at WpfApplication2.App.Main() in c:\Users\Public\Projetos\Outros\WpfApplication3\WpfApplication2\obj\Debug\App.g.cs:line 0
该消息显然是在初始化之前调用IoC类时的预期行为,如我们在Caliburn’s source中所见.但是,在Bootstrapper调用Configure之后,IoC正确初始化.请参阅the source中的BootstrapperBase.StartRuntime方法.
如果我从Bootstrapper中删除所有依赖注入逻辑,该应用程序在Win XP / 7上运行正常.
我花了一些时间试图找到究竟是什么触发了这种行为.我从Bootstrapper中删除了所有内容,经过一些尝试,以下是触发问题所需的全部内容:
public class Bootstrapper : Bootstrapper<Shellviewmodel> { protected override void Configure() { var builder = new ContainerBuilder(); builder.RegisterType<Shellviewmodel>(); } }
如果我注释行builder.RegisterType< Shellviewmodel>();,该应用程序可以正常工作.
结论:在Autofac ContainerBuilder中注册任何内容的简单操作会触发行为.我甚至不需要使用它.我对此完全感到困惑.
我花了好几个小时来解决这个问题.我真的很想使用Caliburn和Autofac,因为我喜欢它们.如果有人能说清楚它,我会很感激.
UPDATE
我注意到如果我在Bootstrapper.Configure方法中调用MessageBox.Show,即使在我的Win8中使用VS2012进行调试,也会发生观察到的行为(“IoC未初始化”):
public class Bootstrapper : Bootstrapper<Shellviewmodel> { protected override void Configure() { MessageBox.Show("Configure"); } }
我正在考虑它,但我还不知道它意味着什么.
UPDATE
Link for the sample application.
UPDATE
在分析观察到的行为之后,我得出结论(正如Sniffer所做的那样)“IoC未初始化”错误的原因不是依赖注入,而是在Bootstrapper启动之前调用MessageBox.Show.
我将MessageBox.Show更改为NLog的日志记录例程,将错误写入文件,然后我就能找到真正的异常.真正的问题来自于Autofac针对PCL以及它与.NET 4.0 Client Profile一起运行的事实,我需要install the update 4.0.3 in target machine.
然而,抛开原来的问题,Caliburn实际上存在问题.在Bootstrapper初始化之前调用MessageBox.Show似乎会触发在IoC配置之间发生的全新Application启动过程,从而生成观察到的异常.
我认为目前的问题偏离了原来的目的,我认为它应该是封闭的.我将在不受特定应用程序问题影响的环境中创建一个针对Caliburn.Micro问题的新问题.
解决方法
现在我想知道为什么在Configure方法中使用MessageBox.Show()方法导致该异常,我想出了原因,并归结为:
> Caliburn.Micro(后来的CM)Bootstrapper< TRootModel>构造函数调用Start()
> Start()调用StartRuntime()
> StartRuntime()按以下特定顺序调用:Configure()然后是IoC.Get = GetInstance,然后是IoC.GetAllInstances = GetAllInstances;然后IoC.BuildUp = BuildUp;
>当StartRuntime()调用Configure()时,你的代码被执行,特别是MessageBox.Show(),这是一个系统函数,它需要(必须)每个消息框都有一个所有者窗口,默认情况下所有者是你当前的活动应用程序窗口.
>现在在这个阶段运行一段系统代码,我不知道正在运行什么,但系统执行的代码调用OnStartup()方法覆盖CM在引导程序中覆盖并使用它显示您选择的TRootModel的视图.
>为了让Caliburn显示该TRootModel的视图,它需要一个IWindowManager的实例,并且它使用(你想通了)我们心爱的IoC,正如你从步骤3中看到的那样,它还没有初始化,它仍然卡在那个Configure()方法上并且没有继续前进.
简介:具有容器配置的代码在我的Win XP机器上没有问题,但配置()覆盖中的MessageBox.Show()方法的代码没有,我给你详细解释了原因.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。