Merge pull request #7839 from umbraco/netcore/feature/ab5820-webprofiler-aspnetcore
NetCore: Implement the WebProfiler for asp.net core.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>8</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
src/Umbraco.Web.Common/Lifetime/IUmbracoRequestLifetime.cs
Normal file
11
src/Umbraco.Web.Common/Lifetime/IUmbracoRequestLifetime.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Web.Common.Lifetime
|
||||
{
|
||||
public interface IUmbracoRequestLifetimeManager
|
||||
{
|
||||
void InitRequest(HttpContext context);
|
||||
void EndRequest(HttpContext context);
|
||||
}
|
||||
}
|
||||
21
src/Umbraco.Web.Common/Lifetime/UmbracoRequestLifetime.cs
Normal file
21
src/Umbraco.Web.Common/Lifetime/UmbracoRequestLifetime.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs
Normal file
29
src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
Normal file
39
src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
Normal 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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
123
src/Umbraco.Web.Common/Runtime/Profiler/WebProfiler.cs
Normal file
123
src/Umbraco.Web.Common/Runtime/Profiler/WebProfiler.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
internal class WebProfilerComposer : ComponentComposer<WebProfilerComponent>, ICoreComposer
|
||||
{
|
||||
}
|
||||
}
|
||||
23
src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
Normal file
23
src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
Normal 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>
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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>");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"AllowedHosts": "*",
|
||||
"Umbraco": {
|
||||
"CMS": {
|
||||
"Hosting": {
|
||||
"Debug": true
|
||||
},
|
||||
"Imaging": {
|
||||
"Resize": {
|
||||
"MaxWidth": 5000,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Web.Logging
|
||||
MiniProfiler.Configure(new MiniProfilerOptions
|
||||
{
|
||||
SqlFormatter = new SqlServerFormatter(),
|
||||
StackMaxLength = 5000,
|
||||
StackMaxLength = 5000,
|
||||
ProfilerProvider = _provider
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Logging
|
||||
{
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user