簡體   English   中英

IoC未在Win7 / XP上初始化

[英]IoC is not initialized on Win7/XP

我試圖在Win7 / XP上運行WPF應用程序時遇到一個非常奇怪的問題。 WPF應用程序面向.NET 4.0,它引用了Caliburn.Micro 1.5.2和Autofac 3.1.0

我將從問題摘要開始,然后我將詳細介紹我到目前為止所得到的內容。

概述

在我的開發工作站我的Windows 8和Visual Studio 2012年我使用的卡利和Autofac在描述這個崗位 (基本上簡化版本 )。

當我在我的開發機器中構建並運行應用程序時,一切都按預期進行。 但是,當我獲取二進制文件並在Windows 7 / XP機器中執行它時,我得到以下錯誤,帶有長堆棧跟蹤:

System.InvalidOperationException: IoC is not initialized

我可以在環境(除OS之外)看到的唯一區別是我的開發工作站有.NET 4.5,而Win7 / XP有.NET 4.0。

細節

我能用一個簡單的應用程序重現這個問題。 解決方案:

在此輸入圖像描述

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一起運行,與一個類似於here描述的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();
    }
}

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

在此輸入圖像描述

我在BootstrapperGetInstance方法中加入了一些斷點,它們被正確命中。

然后,我拿了二進制文件(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, 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

該消息顯然是在初始化之前調用IoC類時的預期行為,我們可以在Caliburn的源代碼中看到。 但是,在Bootstrapper調用Configure之后, IoC正確初始化。 請參閱源中的 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

示例應用程序的鏈接。

UPDATE

在分析了觀察到的行為后,我得出結論(正如Sniffer所做的那樣) “IoC未初始化”錯誤的原因不是依賴注入,而是在Bootstrapper啟動之前調用MessageBox.Show

我將MessageBox.Show更改為NLog的日志記錄例程,將錯誤寫入文件,然后我就能找到真正的異常。 真正的問題來自於Autofac針對PCL並且使用.NET 4.0 Client Profile運行的事實,我需要在目標機器中安裝更新4.0.3

然而,拋開原來的問題,Caliburn實際上存在問題。 在Bootstrapper初始化之前調用MessageBox.Show似乎會觸發在IoC配置之間發生的全新Application啟動過程,從而生成觀察到的異常。

我認為目前的問題偏離了原來的目的,我認為它應該是封閉的。 我將在不受特定應用程序問題影響的環境中創建一個針對Caliburn.Micro問題的新問題。

好吧,我在我的XP機器上運行你的代碼並且你的上次更新有問題,你使用MessageBox類的那個,它導致你的Windows 8機器上出現問題,但是前面的代碼,你創建一個新容器並注冊你說的ShellViewModel在你的win 7 / xp機器上引起了問題並沒有給我帶來任何問題(編譯並運行正常)

現在我想知道為什么在Configure方法中使用MessageBox.Show()方法導致該異常,我想出了原因,並歸結為:

  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在引導程序中覆蓋哪些並使用它來顯示您選擇的TRootModel的視圖。
  6. 為了卡利以顯示該視圖TRootModel它需要一個實例IWindowManager ,並獲得其使用(你想通了),我們敬愛IoC ,你從步數3看哪個,它尚未初始化,它仍然被卡住在那個Configure()方法上並沒有繼續前進。

簡介:具有容器配置的代碼在我的Win XP機器上沒有問題,但Configure()覆蓋MessageBox.Show()方法的代碼沒有 ,我給你詳細解釋了原因。

使用這樣的代碼來顯示來自引導程序的消息:

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

如果配置中發生錯誤,也要阻止執行此行:

DisplayRootViewFor<MainViewModel>();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM