Caliburn-Micro / Caliburn.Micro

A small, yet powerful framework, designed for building applications across all XAML platforms. Its strong support for MV* patterns will enable you to build your solution quickly, without the need to sacrifice code quality or testability.
http://caliburnmicro.com/
MIT License
2.79k stars 777 forks source link

IoC is not initialized #705

Open hjj28810 opened 4 years ago

hjj28810 commented 4 years ago

i update the “cefsharp.wpf” 75.1.14333 to 81.3.100 then can't startup error = IoC is not initialized

nigel-sampson commented 4 years ago

You're going to need to provide some more information here.

hjj28810 commented 4 years ago

system: windows 10 platform: wpf .net framework: 4.8 nuget package: CefSharp.Wpf v81.3.100 Caiburn.Micro v3.2.0 error: IoC is not initialized

ryanvs commented 4 years ago

@hjj28810 can you provide a stack trace? Typically this happens to me when the Bootstrapper.Configure() method throws an exception so the IoC does not finish initialization. Unfortunately the LoaderExceptions in Configure gets buried and you see the IoC is not initialized exception instead. Take a look at any Bootstrapper overrides you have, particularly SelectAssemblies, StartRuntime, and Configure.

HEskandari commented 3 years ago

I have the same issue reported by a user of our application. It apparently happens on Windows Server 2012 R2 (but not other/newer environments such as WinServer 2019). I could not reproduce the error in WinServer 2012 R2 either. This is the second time a user reports back such an issue, and both times they were on non-english locale (which might be orthogonal to this issue). Here's a stack trace:

System.InvalidOperationException: IoC is not initialized.
   at Caliburn.Micro.IoC.<>c.<.cctor>b__5_0(Type service, String key)
   at Caliburn.Micro.IoC.Get[T](String key)
   at Caliburn.Micro.BootstrapperBase.DisplayRootViewFor(Type viewModelType, IDictionary`2 settings)
   at ServiceInsight.Startup.AppBootstrapper.OnStartup(Object sender, StartupEventArgs e) in /_/src/ServiceInsight/Startup/AppBootstrapper.cs:line 118
   at System.Windows.Application.OnStartup(StartupEventArgs e)
   at ServiceInsight.App.OnStartup(StartupEventArgs e) in /_/src/ServiceInsight/App.xaml.cs:line 52
   at System.Windows.Application.<.ctor>b__1_0(Object unused)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

This is a conversation with the user we had.

ryanvs commented 3 years ago

I have seen IoC is not initialized when Initialize or Configure throws an exception. In my case, it is usually due to a dependency failing to load. Looking at the Caliburn source, Initialize loads the PlatformProvider and ExportedTypes, then calls StartRuntime. Then StartRuntime, calls Configure and then sets the IoC functions. So if there are exceptions in Initialize or Configure, then the IoC will not be configured.

I put extra logging (NLog) around my Bootstrapper to help with debugging:

protected override void Configure()
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    _log.Info("Configure entry");
    try
    {
        base.Configure();
    }
    catch (ReflectionTypeLoadException ex)
    {
        string msg = "Bootstrapper.Configure failed - " + ex.Message;
        _log.Error(ex, "Configure failed - {0}", ex.Message);
        foreach (var lex in ex.LoaderExceptions)
        {
            msg += Environment.NewLine + lex.Message;
            _log.Error(lex, "Configure-{0}: {1}", lex.GetType().Name, lex.Message);
        }
        foreach (var t in ex.Types.Where(x => x != null))
        {
            _log.Error("Configure-Type: {0} -> {1}", t.FullName, t.Assembly.Location);
        }
        throw new InvalidProgramException(msg, ex);
    }
    catch (Exception ex)
    {
        string msg = "Bootstrapper.Configure failed - " + ex.Message;
        _log.Error(ex, "Configure failed - {0}", ex.Message);
        throw new InvalidProgramException(msg, ex);
    }
    _log.Info("Configure exit, Elapsed={elapsed}", sw.Elapsed);
}

In my application, I am using Gemini WPF and it uses MEF. I would see these issues sometimes after upgrading NuGet packages, or switching between branches using different versions of assemblies. Also, MEF seems to be slow, and that is why the elapsed time is logged.

I probably should display an error dialog instead of logging and throwing an exception though, so it is more obvious to the end user.

I also noticed MEF does not play nicely with DesignTime, so I overrode the StartDesignTime method to use the default Caliburn IoC methods instead of the Gemini/MEF methods.