Merge pull request #7839 from umbraco/netcore/feature/ab5820-webprofiler-aspnetcore

NetCore: Implement the WebProfiler for asp.net core.
This commit is contained in:
Bjarke Berg
2020-03-31 15:10:18 +02:00
committed by GitHub
43 changed files with 516 additions and 89 deletions

View File

@@ -22,6 +22,6 @@ namespace Umbraco.Configuration.Models
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
public bool DebugMode => _configuration.GetValue(Prefix+":Debug", false);
public bool DebugMode => _configuration.GetValue(Prefix+"Debug", false);
}
}

View File

@@ -23,6 +23,9 @@ namespace Umbraco.Core.Composing
"Umbraco.PublishedCache.NuCache",
"Umbraco.ModelsBuilder.Embedded",
"Umbraco.Examine.Lucene",
"Umbraco.Web.Common",
"Umbraco.Web.BackOffice",
"Umbraco.Web.Website",
};
public DefaultUmbracoAssemblyProvider(Assembly entryPointAssembly)

View File

@@ -1,3 +1,5 @@
using System;
namespace Umbraco.Net
{
// TODO: This shouldn't be in this namespace?
@@ -11,5 +13,13 @@ namespace Umbraco.Net
/// Terminates the current application. The application restarts the next time a request is received for it.
/// </summary>
void Restart();
event EventHandler ApplicationInit;
}
public interface IUmbracoApplicationLifetimeManager
{
void InvokeApplicationInit();
}
}

View File

@@ -146,7 +146,7 @@ namespace Umbraco.Core
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
internal static bool IsClientSideRequest(this Uri url)
public static bool IsClientSideRequest(this Uri url)
{
try
{

View File

@@ -16,6 +16,7 @@ using Umbraco.Core.Runtime;
using Umbraco.Tests.Common;
using Umbraco.Web.BackOffice;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.AspNetCore;
using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Tests.Integration.Implementations

View File

@@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Umbraco.Core.Configuration;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.AspNetCore;
namespace Umbraco.Tests.Integration.Implementations
{
public class TestHostingEnvironment : AspNetCoreHostingEnvironment, Umbraco.Core.Hosting.IHostingEnvironment
{
public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor) : base(hostingSettings, webHostEnvironment, httpContextAccessor)

View File

@@ -1,10 +1,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Moq;
using NUnit.Framework;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Umbraco.Core;
@@ -16,6 +13,7 @@ using Umbraco.Tests.Integration.Extensions;
using Umbraco.Tests.Integration.Implementations;
using Umbraco.Tests.Integration.Testing;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.Extensions;
namespace Umbraco.Tests.Integration
{
@@ -46,11 +44,11 @@ namespace Umbraco.Tests.Integration
// LightInject / Umbraco
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
var umbracoContainer = serviceProviderFactory.GetContainer();
var umbracoContainer = serviceProviderFactory.GetContainer();
// Special case since we are not using the Generic Host, we need to manually add an AspNetCore service to the container
umbracoContainer.Register(x => Mock.Of<IHostApplicationLifetime>());
var testHelper = new TestHelper();
// Create the core runtime
@@ -64,7 +62,7 @@ namespace Umbraco.Tests.Integration
Assert.IsTrue(coreRuntime.MainDom.IsMainDom);
Assert.IsNull(coreRuntime.State.BootFailedException);
Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level);
Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level);
Assert.IsTrue(MyComposer.IsComposed);
Assert.IsFalse(MyComponent.IsInit);
Assert.IsFalse(MyComponent.IsTerminated);
@@ -82,7 +80,7 @@ namespace Umbraco.Tests.Integration
}
/// <summary>
/// Calling AddUmbracoCore to configure the container
/// Calling AddUmbracoCore to configure the container
/// </summary>
[Test]
public async Task AddUmbracoCore()
@@ -209,5 +207,5 @@ namespace Umbraco.Tests.Integration
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
@@ -20,8 +19,8 @@ using Umbraco.Core.Strings;
using Umbraco.Tests.Common.Builders;
using Umbraco.Tests.Integration.Extensions;
using Umbraco.Tests.Integration.Implementations;
using Umbraco.Tests.Testing;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.Extensions;
namespace Umbraco.Tests.Integration.Testing
{

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>8</LangVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -99,7 +99,7 @@
<PackageReference Include="Microsoft.Owin.Security" Version="4.0.1" />
<PackageReference Include="Microsoft.Owin.Testing" Version="4.0.1" />
<PackageReference Include="Microsoft.Web.Infrastructure" Version="1.0.0.0" />
<PackageReference Include="MiniProfiler" Version="4.0.138" />
<PackageReference Include="MiniProfiler" Version="4.1.0" />
<PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="NPoco" Version="4.0.2" />
<PackageReference Include="NUnit" Version="3.12.0" />

View File

@@ -1,27 +0,0 @@
using Microsoft.AspNetCore.Http;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Hosting;
using Umbraco.Net;
using Umbraco.Core.Runtime;
namespace Umbraco.Web.BackOffice.AspNetCore
{
/// <summary>
/// Adds/replaces AspNetCore specific services
/// </summary>
[ComposeBefore(typeof(ICoreComposer))]
[ComposeAfter(typeof(CoreInitialComposer))]
public class AspNetCoreComposer : IComposer
{
public void Compose(Composition composition)
{
// AspNetCore specific services
composition.RegisterUnique<IHttpContextAccessor, HttpContextAccessor>();
// Our own netcore implementations
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetCoreApplicationShutdownRegistry>();
}
}
}

View File

@@ -18,6 +18,7 @@
<ProjectReference Include="..\Umbraco.Configuration\Umbraco.Configuration.csproj" />
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
<ProjectReference Include="..\Umbraco.Web.Common\Umbraco.Web.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -5,7 +5,7 @@ using Microsoft.Extensions.Hosting;
using Umbraco.Core;
using Umbraco.Core.Hosting;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetCoreApplicationShutdownRegistry : IApplicationShutdownRegistry
{

View File

@@ -1,7 +1,7 @@
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetCoreBackOfficeInfo : IBackOfficeInfo
{
@@ -10,7 +10,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
GetAbsoluteUrl = globalSettings.UmbracoPath;
}
public string GetAbsoluteUrl { get; }
public string GetAbsoluteUrl { get; } // TODO make absolute
}
}

View File

@@ -6,16 +6,16 @@ using Microsoft.AspNetCore.Http;
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetCoreHostingEnvironment : Umbraco.Core.Hosting.IHostingEnvironment
{
private readonly IHostingSettings _hostingSettings;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
private string _localTempPath;
public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
@@ -103,7 +103,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
return applicationPath.Add(segment).Value;
}
}

View File

@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Http;
using Umbraco.Net;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetIpResolver : IIpResolver
{

View File

@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using Umbraco.Core.Diagnostics;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetCoreMarchal : IMarchal

View File

@@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Http.Features;
using Umbraco.Net;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
internal class AspNetCoreSessionIdResolver : ISessionIdResolver
{
@@ -13,7 +13,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
_httpContextAccessor = httpContextAccessor;
}
public string SessionId
{
get

View File

@@ -1,11 +1,12 @@
using System;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Umbraco.Net;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.AspNetCore
{
public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime
public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime, IUmbracoApplicationLifetimeManager
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
@@ -32,5 +33,11 @@ namespace Umbraco.Web.BackOffice.AspNetCore
Thread.CurrentPrincipal = null;
_hostApplicationLifetime.StopApplication();
}
public void InvokeApplicationInit()
{
ApplicationInit?.Invoke(this, EventArgs.Empty);
}
public event EventHandler ApplicationInit;
}
}

View File

@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core;
using Umbraco.Core.Cache;
@@ -16,10 +17,11 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Logging.Serilog;
using Umbraco.Core.Persistence;
using Umbraco.Core.Runtime;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Common.Runtime.Profiler;
namespace Umbraco.Web.BackOffice.AspNetCore
namespace Umbraco.Web.Common.Extensions
{
// TODO: Move to Umbraco.Web.Common
public static class UmbracoCoreServiceCollectionExtensions
{
/// <summary>
@@ -69,7 +71,8 @@ namespace Umbraco.Web.BackOffice.AspNetCore
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly)
{
if (services is null) throw new ArgumentNullException(nameof(services));
if (umbContainer is null) throw new ArgumentNullException(nameof(umbContainer));
var container = umbContainer;
if (container is null) throw new ArgumentNullException(nameof(container));
if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly));
// Special case! The generic host adds a few default services but we need to manually add this one here NOW because
@@ -95,7 +98,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
backOfficeInfo,
typeFinder);
var factory = coreRuntime.Configure(umbContainer);
var factory = coreRuntime.Configure(container);
return services;
}
@@ -151,9 +154,26 @@ namespace Umbraco.Web.BackOffice.AspNetCore
new AspNetCoreMarchal());
backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
profiler = new LogProfiler(logger);
profiler = GetWebProfiler(hostingEnvironment, httpContextAccessor);
Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
}
private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment, IHttpContextAccessor httpContextAccessor)
{
// create and start asap to profile boot
if (!hostingEnvironment.IsDebugMode)
{
// should let it be null, that's how MiniProfiler is meant to work,
// but our own IProfiler expects an instance so let's get one
return new VoidProfiler();
}
var webProfiler = new WebProfiler(httpContextAccessor);
webProfiler.StartBoot();
return webProfiler;
}
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
{
public void ThrowIfNotPermissions()
@@ -162,6 +182,6 @@ namespace Umbraco.Web.BackOffice.AspNetCore
}
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using Microsoft.AspNetCore.Builder;
using StackExchange.Profiling;
using Umbraco.Web.Common.Middleware;
namespace Umbraco.Web.Common.Extensions
{
public static class UmbracoRequestApplicationBuilderExtensions
{
public static IApplicationBuilder UseUmbracoRequest(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
app.UseMiddleware<UmbracoRequestMiddleware>();
app.UseMiddleware<MiniProfilerMiddleware>();
return app;
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
using Microsoft.AspNetCore.Http;
namespace Umbraco.Web.Common.Lifetime
{
public interface IUmbracoRequestLifetime
{
event EventHandler<HttpContext> RequestStart;
event EventHandler<HttpContext> RequestEnd;
}
}

View File

@@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Http;
namespace Umbraco.Web.Common.Lifetime
{
public interface IUmbracoRequestLifetimeManager
{
void InitRequest(HttpContext context);
void EndRequest(HttpContext context);
}
}

View File

@@ -0,0 +1,21 @@
using System;
using Microsoft.AspNetCore.Http;
namespace Umbraco.Web.Common.Lifetime
{
public class UmbracoRequestLifetime : IUmbracoRequestLifetime, IUmbracoRequestLifetimeManager
{
public event EventHandler<HttpContext> RequestStart;
public event EventHandler<HttpContext> RequestEnd;
public void InitRequest(HttpContext context)
{
RequestStart?.Invoke(this, context);
}
public void EndRequest(HttpContext context)
{
RequestEnd?.Invoke(this, context);
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Umbraco.Web.Common.Lifetime;
namespace Umbraco.Web.Common.Middleware
{
public class UmbracoRequestMiddleware
{
private readonly RequestDelegate _next;
private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager;
public UmbracoRequestMiddleware(RequestDelegate next, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager)
{
_next = next;
_umbracoRequestLifetimeManager = umbracoRequestLifetimeManager;
}
public async Task InvokeAsync(HttpContext context)
{
_umbracoRequestLifetimeManager.InitRequest(context);
await _next(context);
_umbracoRequestLifetimeManager.EndRequest(context);
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.Extensions.Hosting;
using Umbraco.Core.Composing;
using Umbraco.Net;
namespace Umbraco.Web.Common.Runtime
{
public sealed class AspNetCoreComponent : IComponent
{
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly IUmbracoApplicationLifetimeManager _umbracoApplicationLifetimeManager;
public AspNetCoreComponent(IHostApplicationLifetime hostApplicationLifetime, IUmbracoApplicationLifetimeManager umbracoApplicationLifetimeManager)
{
_hostApplicationLifetime = hostApplicationLifetime;
_umbracoApplicationLifetimeManager = umbracoApplicationLifetimeManager;
}
public void Initialize()
{
_hostApplicationLifetime.ApplicationStarted.Register(() => {
_umbracoApplicationLifetimeManager.InvokeApplicationInit();
});
}
public void Terminate()
{
}
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Http;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Hosting;
using Umbraco.Net;
using Umbraco.Core.Runtime;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Common.Lifetime;
namespace Umbraco.Web.Common.Runtime
{
/// <summary>
/// Adds/replaces AspNetCore specific services
/// </summary>
[ComposeBefore(typeof(ICoreComposer))]
[ComposeAfter(typeof(CoreInitialComposer))]
public class AspNetCoreComposer : ComponentComposer<AspNetCoreComponent>, IComposer
{
public new void Compose(Composition composition)
{
base.Compose(composition);
// AspNetCore specific services
composition.RegisterUnique<IHttpContextAccessor, HttpContextAccessor>();
// Our own netcore implementations
composition.RegisterUnique<AspNetCoreUmbracoApplicationLifetime>();
composition.RegisterUnique<IUmbracoApplicationLifetimeManager>(factory => factory.GetInstance<AspNetCoreUmbracoApplicationLifetime>());
composition.RegisterUnique<IUmbracoApplicationLifetime>(factory => factory.GetInstance<AspNetCoreUmbracoApplicationLifetime>());
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetCoreApplicationShutdownRegistry>();
// The umbraco request lifetime
composition.RegisterUnique<UmbracoRequestLifetime>();
composition.RegisterUnique<IUmbracoRequestLifetimeManager>(factory => factory.GetInstance<UmbracoRequestLifetime>());
composition.RegisterUnique<IUmbracoRequestLifetime>(factory => factory.GetInstance<UmbracoRequestLifetime>());
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using StackExchange.Profiling;
using StackExchange.Profiling.Internal;
using Umbraco.Core;
using Umbraco.Core.Logging;
namespace Umbraco.Web.Common.Runtime.Profiler
{
public class WebProfiler : IProfiler
{
private MiniProfiler _startupProfiler;
private readonly IHttpContextAccessor _httpContextAccessor;
private int _first;
public WebProfiler(IHttpContextAccessor httpContextAccessor)
{
// create our own provider, which can provide a profiler even during boot
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
///
/// </summary>
/// <remarks>
/// Normally we would call MiniProfiler.Current.RenderIncludes(...), but because the requeststate is not set, this method does not work.
/// We fake the requestIds from the RequestState here.
/// </remarks>
public string Render()
{
var profiler = MiniProfiler.Current;
if (profiler == null) return string.Empty;
var context = _httpContextAccessor.HttpContext;
var path = (profiler.Options as MiniProfilerOptions)?.RouteBasePath.Value.EnsureTrailingSlash();
var result = StackExchange.Profiling.Internal.Render.Includes(
profiler,
path: context.Request.PathBase + path,
isAuthorized: true,
requestIDs: new List<Guid>{ profiler.Id },
position: RenderPosition.Right,
showTrivial: profiler.Options.PopupShowTrivial,
showTimeWithChildren: profiler.Options.PopupShowTimeWithChildren,
maxTracesToShow: profiler.Options.PopupMaxTracesToShow,
showControls:profiler.Options.ShowControls,
startHidden: profiler.Options.PopupStartHidden);
return result;
}
public IDisposable Step(string name)
{
return MiniProfiler.Current?.Step(name);
}
public void Start()
{
MiniProfiler.StartNew();
}
public void StartBoot()
{
_startupProfiler = MiniProfiler.StartNew("Startup Profiler");
}
public void StopBoot()
{
_startupProfiler.Stop();
}
public void Stop(bool discardResults = false)
{
MiniProfiler.Current?.Stop(discardResults);
}
public void UmbracoApplicationBeginRequest(HttpContext context)
{
if (ShouldProfile(context.Request))
{
Start();
}
}
public void UmbracoApplicationEndRequest(HttpContext context)
{
if (ShouldProfile(context.Request))
{
Stop();
// if this is the first request, append the startup profiler
var first = Interlocked.Exchange(ref _first, 1) == 0;
if (first)
{
var startupDuration = _startupProfiler.Root.DurationMilliseconds.GetValueOrDefault();
MiniProfiler.Current.DurationMilliseconds += startupDuration;
MiniProfiler.Current.GetTimingHierarchy().First().DurationMilliseconds += startupDuration;
MiniProfiler.Current.Root.AddChild(_startupProfiler.Root);
_startupProfiler = null;
}
}
}
private static bool ShouldProfile(HttpRequest request)
{
if (new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest()) return false;
if (bool.TryParse(request.Query["umbDebug"], out var umbDebug)) return umbDebug;
if (bool.TryParse(request.Headers["X-UMB-DEBUG"], out var xUmbDebug)) return xUmbDebug;
if (bool.TryParse(request.Cookies["UMB-DEBUG"], out var cUmbDebug)) return cUmbDebug;
return false;
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Net;
using Umbraco.Web.Common.Lifetime;
using Umbraco.Web.Common.Middleware;
namespace Umbraco.Web.Common.Runtime.Profiler
{
internal sealed class WebProfilerComponent : IComponent
{
private readonly bool _profile;
private readonly WebProfiler _profiler;
private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
private readonly IUmbracoRequestLifetime _umbracoRequestLifetime;
public WebProfilerComponent(IProfiler profiler, ILogger logger, IUmbracoRequestLifetime umbracoRequestLifetime,
IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
_umbracoRequestLifetime = umbracoRequestLifetime;
_umbracoApplicationLifetime = umbracoApplicationLifetime;
_profile = true;
// although registered in WebRuntime.Compose, ensure that we have not
// been replaced by another component, and we are still "the" profiler
_profiler = profiler as WebProfiler;
if (_profiler != null) return;
// if VoidProfiler was registered, let it be known
if (profiler is VoidProfiler)
logger.Info<WebProfilerComponent>(
"Profiler is VoidProfiler, not profiling (must run debug mode to profile).");
_profile = false;
}
public void Initialize()
{
if (!_profile) return;
// bind to ApplicationInit - ie execute the application initialization for *each* application
// it would be a mistake to try and bind to the current application events
_umbracoApplicationLifetime.ApplicationInit += InitializeApplication;
}
public void Terminate()
{
}
private void InitializeApplication(object sender, EventArgs args)
{
_umbracoRequestLifetime.RequestStart +=
(sender, context) => _profiler.UmbracoApplicationBeginRequest(context);
_umbracoRequestLifetime.RequestEnd += (sender, context) => _profiler.UmbracoApplicationEndRequest(context);
// Stop the profiling of the booting process
_profiler.StopBoot();
}
}
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Core.Composing;
namespace Umbraco.Web.Common.Runtime.Profiler
{
internal class WebProfilerComposer : ComponentComposer<WebProfilerComponent>, ICoreComposer
{
}
}

View File

@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Library</OutputType>
<LangVersion>8</LangVersion>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Configuration\Umbraco.Configuration.csproj" />
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.1.0" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:36804",
"sslPort": 44354
@@ -15,10 +15,11 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Umbraco.Web.UI.BackOffice": {
"Umbraco.Web.UI.NetCore": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"launchBrowser": false,
"applicationUrl": "https://localhost:44354;http://localhost:9000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

View File

@@ -5,10 +5,19 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using StackExchange.Profiling;
using Umbraco.Composing;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Common.Extensions;
using Umbraco.Web.Common.Runtime.Profiler;
using Umbraco.Web.Website.AspNetCore;
@@ -40,24 +49,36 @@ namespace Umbraco.Web.UI.BackOffice
services.AddUmbracoConfiguration(_config);
services.AddUmbracoCore(_webHostEnvironment);
services.AddUmbracoWebsite();
services.AddMvc();
services.AddMiniProfiler(options =>
{
options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// app.UseMiniProfiler();
app.UseUmbracoRequest();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseUmbracoCore();
app.UseUmbracoWebsite();
app.UseUmbracoBackOffice();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); });
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync($"<html><body>Hello World!{Current.Profiler.Render()}</body></html>");
});
});
}
}

View File

@@ -7,6 +7,7 @@
<ItemGroup>
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
<ProjectReference Include="..\Umbraco.Web.Common\Umbraco.Web.Common.csproj" />
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
</ItemGroup>
@@ -14,9 +15,4 @@
<Folder Include="wwwroot\Media" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.hash" />
<_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.list" />
</ItemGroup>
</Project>

View File

@@ -12,6 +12,9 @@
"AllowedHosts": "*",
"Umbraco": {
"CMS": {
"Hosting": {
"Debug": true
},
"Imaging": {
"Resize": {
"MaxWidth": 5000,

View File

@@ -101,7 +101,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MiniProfiler" Version="4.0.138" />
<PackageReference Include="MiniProfiler" Version="4.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="SecurityCodeScan">
<Version>3.4.0</Version>

View File

@@ -1,16 +1,19 @@
using System;
using System.Threading;
using System.Web;
using Umbraco.Net;
namespace Umbraco.Web.AspNet
{
public class AspNetUmbracoApplicationLifetime : IUmbracoApplicationLifetime
public class AspNetUmbracoApplicationLifetime : IUmbracoApplicationLifetimeManager
{
private readonly IHttpContextAccessor _httpContextAccessor;
public AspNetUmbracoApplicationLifetime(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
UmbracoApplicationBase.ApplicationInit += ApplicationInit;
}
public bool IsRestarting { get; set; }
@@ -30,5 +33,11 @@ namespace Umbraco.Web.AspNet
Thread.CurrentPrincipal = null;
HttpRuntime.UnloadAppDomain();
}
public event EventHandler ApplicationInit;
public void InvokeApplicationInit()
{
ApplicationInit?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@@ -104,8 +104,11 @@ namespace Umbraco.Web.Editors
public async Task<ActionResult> Default()
{
return await RenderDefaultOrProcessExternalLoginAsync(
() => View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings,_ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings)),
() => View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings)));
() =>
View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings,_ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings)),
() =>
View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings))
);
}
[HttpGet]

View File

@@ -60,12 +60,14 @@ namespace Umbraco.Web.Install.InstallSteps
var membershipUser = await userManager.FindByIdAsync(Constants.Security.SuperUserId);
if (membershipUser == null)
{
throw new InvalidOperationException($"No user found in membership provider with id of {Constants.Security.SuperUserId}.");
throw new InvalidOperationException(
$"No user found in membership provider with id of {Constants.Security.SuperUserId}.");
}
//To change the password here we actually need to reset it since we don't have an old one to use to change
var resetToken = await userManager.GeneratePasswordResetTokenAsync(membershipUser.Id);
var resetResult = await userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, user.Password.Trim());
var resetResult =
await userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, user.Password.Trim());
if (!resetResult.Succeeded)
{
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors));

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Web.Logging
MiniProfiler.Configure(new MiniProfilerOptions
{
SqlFormatter = new SqlServerFormatter(),
StackMaxLength = 5000,
StackMaxLength = 5000,
ProfilerProvider = _provider
});
}

View File

@@ -1,4 +1,4 @@
using Umbraco.Core.Composing;
 using Umbraco.Core.Composing;
namespace Umbraco.Web.Logging
{

View File

@@ -92,7 +92,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MiniProfiler" Version="4.0.138" />
<PackageReference Include="MiniProfiler" Version="4.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NPoco" Version="4.0.2" />
<PackageReference Include="SecurityCodeScan">

View File

@@ -125,7 +125,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.Integration",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.Common", "Umbraco.Tests.Common\Umbraco.Tests.Common.csproj", "{A499779C-1B3B-48A8-B551-458E582E6E96}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.UnitTests", "Umbraco.Tests.UnitTests\Umbraco.Tests.UnitTests.csproj", "{9102ABDF-E537-4E46-B525-C9ED4833EED0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.Common", "Umbraco.Web.Common\Umbraco.Web.Common.csproj", "{839D3048-9718-4907-BDE0-7CD63D364383}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.UnitTests", "Umbraco.Tests.UnitTests\Umbraco.Tests.UnitTests.csproj", "{3A003230-60B4-4C15-9470-9A77F1BAC1D9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -167,10 +169,6 @@ Global
{FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Release|Any CPU.Build.0 = Release|Any CPU
{9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.Build.0 = Release|Any CPU
{33085570-9BF2-4065-A9B0-A29D920D13BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33085570-9BF2-4065-A9B0-A29D920D13BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33085570-9BF2-4065-A9B0-A29D920D13BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -207,6 +205,14 @@ Global
{A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.Build.0 = Release|Any CPU
{839D3048-9718-4907-BDE0-7CD63D364383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{839D3048-9718-4907-BDE0-7CD63D364383}.Debug|Any CPU.Build.0 = Debug|Any CPU
{839D3048-9718-4907-BDE0-7CD63D364383}.Release|Any CPU.ActiveCfg = Release|Any CPU
{839D3048-9718-4907-BDE0-7CD63D364383}.Release|Any CPU.Build.0 = Release|Any CPU
{3A003230-60B4-4C15-9470-9A77F1BAC1D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A003230-60B4-4C15-9470-9A77F1BAC1D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A003230-60B4-4C15-9470-9A77F1BAC1D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A003230-60B4-4C15-9470-9A77F1BAC1D9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -219,10 +225,10 @@ Global
{53594E5B-64A2-4545-8367-E3627D266AE8} = {FD962632-184C-4005-A5F3-E705D92FC645}
{3A33ADC9-C6C0-4DB1-A613-A9AF0210DF3D} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
{C7311C00-2184-409B-B506-52A5FAEA8736} = {FD962632-184C-4005-A5F3-E705D92FC645}
{9102ABDF-E537-4E46-B525-C9ED4833EED0} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
{FB5676ED-7A69-492C-B802-E7B24144C0FC} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
{D6319409-777A-4BD0-93ED-B2DFD805B32C} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
{A499779C-1B3B-48A8-B551-458E582E6E96} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
{3A003230-60B4-4C15-9470-9A77F1BAC1D9} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7A0F2E34-D2AF-4DAB-86A0-7D7764B3D0EC}