diff --git a/src/Umbraco.Web.UI.Client/src/views/errors/BootFailed.html b/src/Umbraco.Web.UI.Client/src/views/errors/BootFailed.html
new file mode 100644
index 0000000000..c08627739a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/errors/BootFailed.html
@@ -0,0 +1,79 @@
+
+
+
+
+
+ Boot Failed
+
+
+
+
+
+
+
Boot Failed
+
Umbraco failed to boot, if you are the owner of the website please see the log file for more details.
+
+
+
+
diff --git a/src/Umbraco.Web/Composing/ModuleInjector.cs b/src/Umbraco.Web/Composing/ModuleInjector.cs
index 57ef766dea..41540d196c 100644
--- a/src/Umbraco.Web/Composing/ModuleInjector.cs
+++ b/src/Umbraco.Web/Composing/ModuleInjector.cs
@@ -35,7 +35,16 @@ namespace Umbraco.Web.Composing
catch { /* don't make it worse */ }
if (runtimeState?.BootFailedException != null)
- BootFailedException.Rethrow(runtimeState.BootFailedException);
+ {
+ // if we throw the exception here the HttpApplication.Application_Error method will never be hit
+ // and our custom error page will not be shown, so we need to wait for the request to begin
+ // before we throw the exception.
+ context.BeginRequest += (sender, args) =>
+ {
+ BootFailedException.Rethrow(runtimeState.BootFailedException);
+ };
+ return;
+ }
// else... throw what we have
throw;
diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs
index f70651a43e..c96e21e348 100644
--- a/src/Umbraco.Web/UmbracoApplication.cs
+++ b/src/Umbraco.Web/UmbracoApplication.cs
@@ -1,7 +1,10 @@
-using System.Configuration;
+using System;
+using System.Configuration;
+using System.IO;
using System.Threading;
using System.Web;
using Umbraco.Core;
+using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Logging.Serilog;
using Umbraco.Core.Runtime;
@@ -23,6 +26,53 @@ namespace Umbraco.Web
return runtime;
}
+ protected override void OnApplicationError(object sender, EventArgs evargs)
+ {
+ base.OnApplicationError(sender, evargs);
+
+ // if the exception is a BootFailedException we want to show a custom 500 page
+ if (Server.GetLastError() is BootFailedException)
+ {
+ // if the requested file exists on disk, clear the error and return
+ // this is needed to serve static files
+ if (File.Exists(Request.PhysicalPath))
+ {
+ Server.ClearError();
+ return;
+ }
+
+ // if the application is in debug mode we don't want to show the custom 500 page
+ if (Context.IsDebuggingEnabled) return;
+
+ // find the error file to show
+ var fileName = GetBootErrorFileName();
+
+ // if the file doesn't exist we return and a YSOD will be shown
+ if (File.Exists(fileName) == false) return;
+
+ Response.TrySkipIisCustomErrors = true;
+ Server.ClearError();
+ Response.Clear();
+
+ Response.StatusCode = 500;
+ Response.ContentType = "text/html";
+ Response.WriteFile(fileName);
+
+ CompleteRequest();
+ }
+ }
+
+ ///
+ /// Returns the absolute filename to the BootException html file.
+ ///
+ protected virtual string GetBootErrorFileName()
+ {
+ var fileName = Server.MapPath("~/config/errors/BootFailed.html");
+ if (File.Exists(fileName)) return fileName;
+
+ return Server.MapPath("~/umbraco/views/errors/BootFailed.html");
+ }
+
///
/// Returns a new MainDom
///
diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs
index 59b5b1779b..32a949e972 100644
--- a/src/Umbraco.Web/UmbracoApplicationBase.cs
+++ b/src/Umbraco.Web/UmbracoApplicationBase.cs
@@ -6,7 +6,6 @@ using System.Web.Hosting;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
-using Umbraco.Core.Logging.Serilog;
namespace Umbraco.Web
{
diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs
index 6eeef081a2..92fee22983 100644
--- a/src/Umbraco.Web/UmbracoInjectedModule.cs
+++ b/src/Umbraco.Web/UmbracoInjectedModule.cs
@@ -357,15 +357,13 @@ namespace Umbraco.Web
// there's nothing we can do really
app.BeginRequest += (sender, args) =>
{
- // would love to avoid throwing, and instead display a customized Umbraco 500
- // page - however if we don't throw here, something else might go wrong, and
- // it's this later exception that would be reported. could not figure out how
- // to prevent it, either with httpContext.Response.End() or .ApplicationInstance
- // .CompleteRequest()
+ // if we don't throw here, something else might go wrong,
+ // and it's this later exception that would be reported.
// 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
+ // the exception is handled in UmbracoApplication which shows a custom error page
BootFailedException.Rethrow(Core.Composing.Current.RuntimeState.BootFailedException);
};
return;