diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index dc94fa3dc841..e44a7449aa5a 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -109,7 +109,7 @@ public static IUmbracoBuilder AddUmbraco( services.ConfigureOptions(); services.ConfigureOptions(); - IProfiler profiler = GetWebProfiler(config); + IProfiler profiler = GetWebProfiler(config, httpContextAccessor); services.AddLogger(webHostEnvironment, config); @@ -200,15 +200,8 @@ public static IUmbracoBuilder AddUmbracoProfiler(this IUmbracoBuilder builder) { builder.Services.AddSingleton(); - builder.Services.AddMiniProfiler(options => - { - // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile - options.ShouldProfile = request => false; - - // this is a default path and by default it performs a 'contains' check which will match our content controller - // (and probably other requests) and ignore them. - options.IgnoredPaths.Remove("/content/"); - }); + builder.Services.AddMiniProfiler(); + builder.Services.ConfigureOptions(); builder.AddNotificationHandler(); return builder; @@ -385,7 +378,7 @@ public static IUmbracoBuilder AddWebServer(this IUmbracoBuilder builder) return builder; } - private static IProfiler GetWebProfiler(IConfiguration config) + private static IProfiler GetWebProfiler(IConfiguration config, IHttpContextAccessor httpContextAccessor) { var isDebug = config.GetValue($"{Constants.Configuration.ConfigHosting}:Debug"); @@ -397,7 +390,7 @@ private static IProfiler GetWebProfiler(IConfiguration config) return new NoopProfiler(); } - var webProfiler = new WebProfiler(); + var webProfiler = new WebProfiler(httpContextAccessor); webProfiler.StartBoot(); return webProfiler; diff --git a/src/Umbraco.Web.Common/Profiler/ConfigureMiniProfilerOptions.cs b/src/Umbraco.Web.Common/Profiler/ConfigureMiniProfilerOptions.cs new file mode 100644 index 000000000000..4239ba1737f3 --- /dev/null +++ b/src/Umbraco.Web.Common/Profiler/ConfigureMiniProfilerOptions.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using StackExchange.Profiling; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Security; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Web.Common.Profiler; + +internal sealed class ConfigureMiniProfilerOptions : IConfigureOptions +{ + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + private readonly string _backOfficePath; + + public ConfigureMiniProfilerOptions( + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment) + { + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + _backOfficePath = globalSettings.Value.GetBackOfficePath(hostingEnvironment); + } + + public void Configure(MiniProfilerOptions options) + { + options.RouteBasePath = WebPath.Combine(_backOfficePath, "profiler"); + // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile + options.ShouldProfile = request => false; + + options.IgnoredPaths.Clear(); + options.IgnoredPaths.Add(WebPath.Combine(_backOfficePath, "swagger")); + options.IgnoredPaths.Add(WebPath.Combine(options.RouteBasePath, "results-list")); + options.IgnoredPaths.Add(WebPath.Combine(options.RouteBasePath, "results-index")); + options.IgnoredPaths.Add(WebPath.Combine(options.RouteBasePath, "results")); + + options.ResultsAuthorize = IsBackofficeUserAuthorized; + options.ResultsListAuthorize = IsBackofficeUserAuthorized; + } + + private bool IsBackofficeUserAuthorized(HttpRequest request) => true;// FIXME when we can get current backoffice user, _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser is not null; +} diff --git a/src/Umbraco.Web.Common/Profiler/WebProfiler.cs b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs index 9608bad71521..50a0de19a9c9 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfiler.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs @@ -1,6 +1,7 @@ using System.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using StackExchange.Profiling; @@ -14,6 +15,14 @@ namespace Umbraco.Cms.Web.Common.Profiler; public class WebProfiler : IProfiler { + private readonly IHttpContextAccessor _httpContextAccessor; + + public WebProfiler(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public static readonly AsyncLocal MiniProfilerContext = new(x => { _ = x; @@ -24,11 +33,12 @@ public class WebProfiler : IProfiler private int _first; private MiniProfiler? _startupProfiler; - public IDisposable? Step(string name) => MiniProfiler.Current?.Step(name); + public IDisposable? Step(string name) => + MiniProfiler.Current?.Step(name); public void Start() { - MiniProfiler.StartNew(); + MiniProfiler.StartNew(_httpContextAccessor.HttpContext?.Request.Path); MiniProfilerContext.Value = MiniProfiler.Current; } @@ -75,7 +85,6 @@ public void UmbracoApplicationEndRequest(HttpContext context, RuntimeLevel runti { AddSubProfiler(_startupProfiler); } - _startupProfiler = null; } @@ -102,13 +111,20 @@ public void UmbracoApplicationEndRequest(HttpContext context, RuntimeLevel runti private static ICookieManager GetCookieManager(HttpContext context) => context.RequestServices.GetRequiredService(); - private static bool ShouldProfile(HttpRequest request) + private bool ShouldProfile(HttpRequest request) { if (request.IsClientSideRequest()) { return false; } + var miniprofilerOptions = _httpContextAccessor.HttpContext?.RequestServices?.GetService>(); + if (miniprofilerOptions is not null && miniprofilerOptions.Value.IgnoredPaths.Contains(request.Path)) + { + return false; + } + + if (bool.TryParse(request.Query["umbDebug"], out var umbDebug)) { return umbDebug;