diff --git a/src/Umbraco.Core/Exceptions/BootFailedException.cs b/src/Umbraco.Core/Exceptions/BootFailedException.cs index ec07389d37..10a648fd76 100644 --- a/src/Umbraco.Core/Exceptions/BootFailedException.cs +++ b/src/Umbraco.Core/Exceptions/BootFailedException.cs @@ -1,9 +1,10 @@ using System; +using System.Text; namespace Umbraco.Core.Exceptions { /// - /// An exception that is thrown if the Umbraco application cannnot boot. + /// An exception that is thrown if the Umbraco application cannot boot. /// public class BootFailedException : Exception { @@ -29,5 +30,31 @@ namespace Umbraco.Core.Exceptions public BootFailedException(string message, Exception inner) : base(message, inner) { } + + /// + /// Rethrows a captured . + /// + /// The exception can be null, in which case a default message is used. + public static void Rethrow(BootFailedException bootFailedException) + { + if (bootFailedException == null) + throw new BootFailedException(DefaultMessage); + + // see https://stackoverflow.com/questions/57383 + // would that be the correct way to do it? + //ExceptionDispatchInfo.Capture(bootFailedException).Throw(); + + Exception e = bootFailedException; + var m = new StringBuilder(); + m.Append(DefaultMessage); + while (e != null) + { + m.Append($"\n\n-> {e.GetType().FullName}: {e.Message}"); + if (string.IsNullOrWhiteSpace(e.StackTrace) == false) + m.Append($"\n{e.StackTrace}"); + e = e.InnerException; + } + throw new BootFailedException(m.ToString()); + } } } diff --git a/src/Umbraco.Web/Composing/ModuleInjector.cs b/src/Umbraco.Web/Composing/ModuleInjector.cs index 8ff8f407e1..c415d5ca6e 100644 --- a/src/Umbraco.Web/Composing/ModuleInjector.cs +++ b/src/Umbraco.Web/Composing/ModuleInjector.cs @@ -2,6 +2,7 @@ using System.Web; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Exceptions; namespace Umbraco.Web.Composing { @@ -21,16 +22,28 @@ namespace Umbraco.Web.Composing { // using the service locator here - no other way, really Module = Current.Container.GetInstance(); - Module.Init(context); } catch { - var runtimeState = Current.Container.GetInstance(); - if (runtimeState.BootFailedException != null) + // if GetInstance fails, it may be because of a boot error, in + // which case that is the error we actually want to report + IRuntimeState runtimeState = null; + + try { - throw new Exception("Failed to boot", runtimeState.BootFailedException); + runtimeState = Current.Container.GetInstance(); } + catch { /* don't make it worse */ } + + if (runtimeState?.BootFailedException != null) + BootFailedException.Rethrow(runtimeState.BootFailedException); + + // else... throw what we have + throw; } + + // initialize + Module.Init(context); } /// diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs index 11670df51b..23d3e2fb5a 100644 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ b/src/Umbraco.Web/UmbracoInjectedModule.cs @@ -13,6 +13,7 @@ using Umbraco.Web.Routing; using Umbraco.Web.Security; using Umbraco.Core.Exceptions; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Composing; @@ -458,19 +459,7 @@ namespace Umbraco.Web // also, if something goes wrong with our DI setup, the logging subsystem may // not even kick in, so here we try to give as much detail as possible - Exception e = Core.Composing.Current.RuntimeState.BootFailedException; - if (e == null) - throw new BootFailedException(BootFailedException.DefaultMessage); - var m = new StringBuilder(); - m.Append(BootFailedException.DefaultMessage); - while (e != null) - { - m.Append($"\n\n-> {e.GetType().FullName}: {e.Message}"); - if (string.IsNullOrWhiteSpace(e.StackTrace) == false) - m.Append($"\n{e.StackTrace}"); - e = e.InnerException; - } - throw new BootFailedException(m.ToString()); + BootFailedException.Rethrow(Core.Composing.Current.RuntimeState.BootFailedException); }; return; }