diff --git a/src/Umbraco.Core/Profiling/StartupWebProfilerProvider.cs b/src/Umbraco.Core/Profiling/StartupWebProfilerProvider.cs
new file mode 100644
index 0000000000..16ce638c0e
--- /dev/null
+++ b/src/Umbraco.Core/Profiling/StartupWebProfilerProvider.cs
@@ -0,0 +1,126 @@
+using System.Threading;
+using System.Web;
+using StackExchange.Profiling;
+
+namespace Umbraco.Core.Profiling
+{
+ ///
+ /// Allows us to profile items during app startup - before an HttpRequest is created
+ ///
+ internal class StartupWebProfilerProvider : WebRequestProfilerProvider
+ {
+ public StartupWebProfilerProvider()
+ {
+ _startupPhase = StartupPhase.Boot;
+ //create the startup profiler
+ _startupProfiler = new MiniProfiler("http://localhost/umbraco-startup", ProfileLevel.Verbose)
+ {
+ Name = "StartupProfiler"
+ };
+ }
+
+ private MiniProfiler _startupProfiler;
+ private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
+
+ private enum StartupPhase
+ {
+ None = 0,
+ Boot = 1,
+ Request = 2
+ }
+
+ private volatile StartupPhase _startupPhase;
+
+ public void BootComplete()
+ {
+ using (new ReadLock(_locker))
+ {
+ if (_startupPhase != StartupPhase.Boot) return;
+ }
+
+ using (var l = new UpgradeableReadLock(_locker))
+ {
+ if (_startupPhase == StartupPhase.Boot)
+ {
+ l.UpgradeToWriteLock();
+
+ ////Now we need to transfer some information from our startup phase to the normal
+ ////web request phase to output the startup profiled information.
+ ////Stop our internal startup profiler, this will write out it's results to storage.
+ //StopProfiler(_startupProfiler);
+ //SaveProfiler(_startupProfiler);
+
+ _startupPhase = StartupPhase.Request;
+ }
+ }
+ }
+
+ public override void Stop(bool discardResults)
+ {
+ using (new ReadLock(_locker))
+ {
+ if (_startupPhase == StartupPhase.None)
+ {
+ base.Stop(discardResults);
+ return;
+ }
+ }
+
+ using (var l = new UpgradeableReadLock(_locker))
+ {
+ if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
+ {
+ l.UpgradeToWriteLock();
+
+ _startupPhase = StartupPhase.None;
+
+ if (HttpContext.Current != null)
+ {
+ HttpContext.Current.Items[":mini-profiler:"] = _startupProfiler;
+ base.Stop(discardResults);
+ _startupProfiler = null;
+ }
+ }
+ else
+ {
+ base.Stop(discardResults);
+ }
+ }
+ }
+
+ public override MiniProfiler Start(ProfileLevel level)
+ {
+ using (new ReadLock(_locker))
+ {
+ if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
+ {
+ SetProfilerActive(_startupProfiler);
+ return _startupProfiler;
+ }
+
+ return base.Start(level);
+ }
+ }
+
+ public override MiniProfiler GetCurrentProfiler()
+ {
+ using (new ReadLock(_locker))
+ {
+ if (_startupPhase > 0)
+ {
+ try
+ {
+ var current = base.GetCurrentProfiler();
+ if (current == null) return _startupProfiler;
+ }
+ catch
+ {
+ return _startupProfiler;
+ }
+ }
+
+ return base.GetCurrentProfiler();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Profiling/WebProfiler.cs b/src/Umbraco.Core/Profiling/WebProfiler.cs
index 00d088bca7..7e2cf49313 100644
--- a/src/Umbraco.Core/Profiling/WebProfiler.cs
+++ b/src/Umbraco.Core/Profiling/WebProfiler.cs
@@ -12,15 +12,24 @@ namespace Umbraco.Core.Profiling
///
internal class WebProfiler : IProfiler
{
+ private StartupWebProfilerProvider _startupWebProfilerProvider;
///
/// Constructor
- ///
- ///
- /// Binds to application events to enable the MiniProfiler
- ///
+ ///
internal WebProfiler()
{
+ //setup some defaults
+ MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
+ MiniProfiler.Settings.StackMaxLength = 5000;
+
+ //At this point we know that we've been constructed during app startup, there won't be an HttpRequest in the HttpContext
+ // since it hasn't started yet. So we need to do some hacking to enable profiling during startup.
+ _startupWebProfilerProvider = new StartupWebProfilerProvider();
+ //this should always be the case during startup, we'll need to set a custom profiler provider
+ MiniProfiler.Settings.ProfilerProvider = _startupWebProfilerProvider;
+
+ //Binds to application events to enable the MiniProfiler with a real HttpRequest
UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit;
}
@@ -53,7 +62,12 @@ namespace Umbraco.Core.Profiling
///
void UmbracoApplicationEndRequest(object sender, EventArgs e)
{
- if (CanPerformProfilingAction(sender))
+ if (_startupWebProfilerProvider != null)
+ {
+ Stop();
+ _startupWebProfilerProvider = null;
+ }
+ else if (CanPerformProfilingAction(sender))
{
Stop();
}
@@ -66,6 +80,11 @@ namespace Umbraco.Core.Profiling
///
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
{
+ if (_startupWebProfilerProvider != null)
+ {
+ _startupWebProfilerProvider.BootComplete();
+ }
+
if (CanPerformProfilingAction(sender))
{
Start();
@@ -124,9 +143,7 @@ namespace Umbraco.Core.Profiling
/// Start the profiler
///
public void Start()
- {
- MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
- MiniProfiler.Settings.StackMaxLength = 5000;
+ {
MiniProfiler.Start();
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 2ef0501f8e..d11270592a 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -469,6 +469,7 @@
+
diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs
index dcf1e98be4..a9495afa7c 100644
--- a/src/Umbraco.Web/WebBootManager.cs
+++ b/src/Umbraco.Web/WebBootManager.cs
@@ -183,7 +183,9 @@ namespace Umbraco.Web
base.InitializeProfilerResolver();
//Set the profiler to be the web profiler
- ProfilerResolver.Current.SetProfiler(new WebProfiler());
+ var profiler = new WebProfiler();
+ ProfilerResolver.Current.SetProfiler(profiler);
+ profiler.Start();
}
///