1
1
using System ;
2
2
using System . Linq ;
3
+ using System . Net ;
3
4
using System . Threading ;
4
5
using Microsoft . AspNetCore . Http ;
6
+ using Microsoft . AspNetCore . Mvc . ViewFeatures ;
7
+ using Microsoft . Extensions . DependencyInjection ;
5
8
using StackExchange . Profiling ;
9
+ using StackExchange . Profiling . Internal ;
6
10
using Umbraco . Cms . Core ;
7
11
using Umbraco . Cms . Core . Logging ;
8
12
using Umbraco . Cms . Core . Services ;
13
+ using Umbraco . Cms . Core . Web ;
9
14
using Umbraco . Extensions ;
10
15
11
16
namespace Umbraco . Cms . Web . Common . Profiler
12
17
{
13
18
14
19
public class WebProfiler : IProfiler
15
20
{
21
+ private const string WebProfileCookieKey = "umbracoWebProfiler" ;
22
+
16
23
public static readonly AsyncLocal < MiniProfiler > MiniProfilerContext = new AsyncLocal < MiniProfiler > ( x =>
17
24
{
18
25
_ = x ;
@@ -39,7 +46,6 @@ public void Start()
39
46
40
47
public void Stop ( bool discardResults = false ) => MiniProfilerContext . Value ? . Stop ( discardResults ) ;
41
48
42
-
43
49
public void UmbracoApplicationBeginRequest ( HttpContext context , RuntimeLevel runtimeLevel )
44
50
{
45
51
if ( runtimeLevel != RuntimeLevel . Run )
@@ -50,9 +56,13 @@ public void UmbracoApplicationBeginRequest(HttpContext context, RuntimeLevel run
50
56
if ( ShouldProfile ( context . Request ) )
51
57
{
52
58
Start ( ) ;
59
+ ICookieManager cookieManager = GetCookieManager ( context ) ;
60
+ cookieManager . ExpireCookie ( WebProfileCookieKey ) ; //Ensure we expire the cookie, so we do not reuse the old potential value saved
53
61
}
54
62
}
55
63
64
+ private static ICookieManager GetCookieManager ( HttpContext context ) => context . RequestServices . GetRequiredService < ICookieManager > ( ) ;
65
+
56
66
public void UmbracoApplicationEndRequest ( HttpContext context , RuntimeLevel runtimeLevel )
57
67
{
58
68
if ( runtimeLevel != RuntimeLevel . Run )
@@ -70,19 +80,42 @@ public void UmbracoApplicationEndRequest(HttpContext context, RuntimeLevel runti
70
80
var first = Interlocked . Exchange ( ref _first , 1 ) == 0 ;
71
81
if ( first )
72
82
{
73
-
74
- var startupDuration = _startupProfiler . Root . DurationMilliseconds . GetValueOrDefault ( ) ;
75
- MiniProfilerContext . Value . DurationMilliseconds += startupDuration ;
76
- MiniProfilerContext . Value . GetTimingHierarchy ( ) . First ( ) . DurationMilliseconds += startupDuration ;
77
- MiniProfilerContext . Value . Root . AddChild ( _startupProfiler . Root ) ;
83
+ AddSubProfiler ( _startupProfiler ) ;
78
84
79
85
_startupProfiler = null ;
80
86
}
87
+
88
+ ICookieManager cookieManager = GetCookieManager ( context ) ;
89
+ var cookieValue = cookieManager . GetCookieValue ( WebProfileCookieKey ) ;
90
+
91
+ if ( cookieValue is not null )
92
+ {
93
+ AddSubProfiler ( MiniProfiler . FromJson ( cookieValue ) ) ;
94
+ }
95
+
96
+ //If it is a redirect to a relative path (local redirect)
97
+ if ( context . Response . StatusCode == ( int ) HttpStatusCode . Redirect
98
+ && context . Response . Headers . TryGetValue ( Microsoft . Net . Http . Headers . HeaderNames . Location , out var location )
99
+ && ! location . Contains ( "://" ) )
100
+ {
101
+ MiniProfilerContext . Value . Root . Name = "Before Redirect" ;
102
+ cookieManager . SetCookieValue ( WebProfileCookieKey , MiniProfilerContext . Value . ToJson ( ) ) ;
103
+ }
104
+
81
105
}
82
106
83
107
}
84
108
}
85
109
110
+ private void AddSubProfiler ( MiniProfiler subProfiler )
111
+ {
112
+ var startupDuration = subProfiler . Root . DurationMilliseconds . GetValueOrDefault ( ) ;
113
+ MiniProfilerContext . Value . DurationMilliseconds += startupDuration ;
114
+ MiniProfilerContext . Value . GetTimingHierarchy ( ) . First ( ) . DurationMilliseconds += startupDuration ;
115
+ MiniProfilerContext . Value . Root . AddChild ( subProfiler . Root ) ;
116
+
117
+ }
118
+
86
119
private static bool ShouldProfile ( HttpRequest request )
87
120
{
88
121
if ( request . IsClientSideRequest ( ) ) return false ;
0 commit comments