IoC未在Win7 / XP上初始化

时间:2013-07-12 19:23:25

标签: c# wpf .net-4.0 autofac caliburn.micro

我正试图在Win7 / XP上运行WPF应用程序时遇到一个非常奇怪的问题。 WPF应用程序面向.NET 4.0,它引用了Caliburn.Micro 1.5.2和Autofac 3.1.0

我将从问题摘要开始,然后我将详细介绍我到目前为止所做的事情。

概览

在我的开发工作站中,我有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。

详情

我能用一个简单的应用程序重现这个问题。解决方案:

enter image description here

ShellViewModel只是一个空Conductor<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>

修改了App.xaml.cs代码以捕获并显示异常:

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类似于描述here的{​​{1}}。例如,我创建了一个简化版本:

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();
    }
}

在我的工作站中,它运行得很好:

enter image description here

我在Bootstrapper的{​​{1}}方法中添加了一些断点,并且它们被正确命中。

然后,我拿了二进制文件(bin / Debug)并尝试在Windows XP / 7虚拟机中运行它们。应用程序无法启动,我收到以下异常:

GetInstance

该消息显然是在初始化之前调用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, Object args, 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, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, 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, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.MessageBox(HandleRef hWnd, String text, String caption, Int32 type) at System.Windows.MessageBox.ShowCore(IntPtr owner, String messageBoxText, String caption, 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 类时的预期行为,我们可以在Caliburn's source中看到。但是,IoCIoC调用Bootstrapper后正确初始化Configure。请参阅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,因为我喜欢它们。如果有人能说清楚它,我会很感激。

更新

我注意到如果我在Bootstrapper.Configure方法中调用MessageBox.Show,即使在我的Win8中使用VS2012进行调试,也会发生观察到的行为(“IoC未初始化”):

public class Bootstrapper : Bootstrapper<ShellViewModel>
{
    protected override void Configure()
    {
        MessageBox.Show("Configure");
    }
}

我正在考虑它,但我还不知道它意味着什么。

更新

Link for the sample application.

更新

在分析观察到的行为后,我得出结论(正如Sniffer所做的那样)“IoC未初始化”的原因错误不是依赖注入,而是在MessageBox.Show之前调用Bootstrapper {1}}启动。

我将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问题的新问题。

2 个答案:

答案 0 :(得分:1)

我在我的XP机器上运行你的代码并且上次更新时出现问题,你使用MessageBox类的问题导致你在Windows 8机器上出现问题,但是前面的代码在哪里你创建一个新的容器并注册你所说的导致问题的ShellViewModel你的win 7 / xp机器导致我任何问题(它编译并运行正常)

现在我想知道为什么在MessageBox.Show()方法中使用Configure方法会导致该异常,我有点想出了原因并且归结为:

  1. Caliburn.Micro的(后面的CM) Bootstrapper<TRootModel>构造函数正在调用Start()
  2. Start()正在调用StartRuntime()
  3. StartRuntime()正按此特定顺序进行调用:Configure()然后IoC.Get = GetInstance然后IoC.GetAllInstances = GetAllInstances;然后IoC.BuildUp = BuildUp;
  4. StartRuntime()调用Configure()代码执行时,具体为MessageBox.Show(),这是需要的系统功能 (必须) 每个消息框都有一个所有者窗口,默认情况下所有者是您当前的活动应用程序窗口。
  5. 现在在这个阶段运行一段系统代码,我不知道正在运行什么,但是系统执行的代码调用OnStartup()方法覆盖,CM覆盖了bootstrapper并使用它来显示您选择的TRootModel的视图。
  6. 为了让Caliburn显示该TRootModel的视图,它需要一个IWindowManager的实例并获得它使用(你想出来的)我们心爱的{ {1}}正如您从第3步所看到的那样,尚未已初始化,它仍然停留在IoC方法上并且尚未继续。
  7. 摘要:包含容器配置的代码在我的Win XP计算机上没有问题,但Configure()覆盖中使用MessageBox.Show()方法的代码确实有效不,我给你详细解释了原因。

答案 1 :(得分:0)

使用这样的代码来显示来自引导程序的消息:

Execute.OnUIThread(() =>
{
    MessageBox.Show(m);
});

如果在Configure:

中发生错误,也不要执行此行
DisplayRootViewFor<MainViewModel>();