AB#5820 - Introduced WebProfiler for asp.net core
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Net
|
||||
{
|
||||
public interface IUmbracoApplicationLifetime
|
||||
@@ -10,5 +12,7 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
@@ -14,6 +15,11 @@ namespace Umbraco.Web.AspNet
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
|
||||
hostApplicationLifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
ApplicationInit?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsRestarting { get; set; }
|
||||
@@ -32,5 +38,7 @@ namespace Umbraco.Web.AspNet
|
||||
Thread.CurrentPrincipal = null;
|
||||
_hostApplicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
public event EventHandler ApplicationInit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
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>();
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.Common.Extensions
|
||||
{
|
||||
public static class UmbracoRequestServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddUmbracoRequest(this IServiceCollection services)
|
||||
{
|
||||
var umbracoRequestLifetime = new UmbracoRequestLifetime();
|
||||
|
||||
services.AddSingleton<IUmbracoRequestLifetimeManager>(umbracoRequestLifetime);
|
||||
services.AddSingleton<IUmbracoRequestLifetime>(umbracoRequestLifetime);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IUmbracoRequestLifetime
|
||||
{
|
||||
event EventHandler<HttpContext> RequestStart;
|
||||
event EventHandler<HttpContext> RequestEnd;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IUmbracoRequestLifetimeManager
|
||||
{
|
||||
void InitRequest(HttpContext context);
|
||||
void EndRequest(HttpContext context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using StackExchange.Profiling;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
public class WebProfiler : IProfiler
|
||||
{
|
||||
private const string BootRequestItemKey = "Umbraco.Core.Logging.WebProfiler__isBootRequest";
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly WebProfilerProvider _provider;
|
||||
private int _first;
|
||||
|
||||
public WebProfiler(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
// create our own provider, which can provide a profiler even during boot
|
||||
_provider = new WebProfilerProvider();
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string Render() => MiniProfiler.Current
|
||||
.RenderIncludes(_httpContextAccessor.HttpContext, RenderPosition.Right).ToString();
|
||||
|
||||
public IDisposable Step(string name) => MiniProfiler.Current?.Step(name);
|
||||
|
||||
public void Start()
|
||||
{
|
||||
MiniProfiler.StartNew();
|
||||
}
|
||||
|
||||
public void Stop(bool discardResults = false)
|
||||
{
|
||||
MiniProfiler.Current?.Stop(discardResults);
|
||||
}
|
||||
|
||||
public void UmbracoApplicationBeginRequest(HttpContext context)
|
||||
{
|
||||
// if this is the first request, notify our own provider that this request is the boot request
|
||||
var first = Interlocked.Exchange(ref _first, 1) == 0;
|
||||
if (first)
|
||||
{
|
||||
_provider.BeginBootRequest();
|
||||
context.Items[BootRequestItemKey] = true;
|
||||
// and no need to start anything, profiler is already there
|
||||
}
|
||||
// else start a profiler, the normal way
|
||||
else if (ShouldProfile(context.Request))
|
||||
Start();
|
||||
}
|
||||
|
||||
public void UmbracoApplicationEndRequest(HttpContext context)
|
||||
{
|
||||
// if this is the boot request, or if we should profile this request, stop
|
||||
// (the boot request is always profiled, no matter what)
|
||||
if (context.Items.TryGetValue(BootRequestItemKey, out var isBoot) && isBoot.Equals(true))
|
||||
{
|
||||
_provider.EndBootRequest();
|
||||
Stop();
|
||||
}
|
||||
else if (ShouldProfile(context.Request))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
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,55 @@
|
||||
using System;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Net;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
internal class WebProfilerComposer : ComponentComposer<WebProfilerComponent>, ICoreComposer
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using StackExchange.Profiling;
|
||||
using StackExchange.Profiling.Internal;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime.Profiler
|
||||
{
|
||||
public class WebProfilerProvider : DefaultProfilerProvider
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
|
||||
private volatile BootPhase _bootPhase;
|
||||
private int _first;
|
||||
private MiniProfiler _startupProfiler;
|
||||
|
||||
public WebProfilerProvider()
|
||||
{
|
||||
// booting...
|
||||
_bootPhase = BootPhase.Boot;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current profiler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the boot phase is not Booted, then this will return the startup profiler (this), otherwise
|
||||
/// returns the base class
|
||||
/// </remarks>
|
||||
public override MiniProfiler CurrentProfiler
|
||||
{
|
||||
get
|
||||
{
|
||||
// if not booting then just use base (fast)
|
||||
// no lock, _bootPhase is volatile
|
||||
if (_bootPhase == BootPhase.Booted)
|
||||
return base.CurrentProfiler;
|
||||
|
||||
// else
|
||||
try
|
||||
{
|
||||
var current = base.CurrentProfiler;
|
||||
return current ?? _startupProfiler;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return _startupProfiler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginBootRequest()
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
if (_bootPhase != BootPhase.Boot)
|
||||
throw new InvalidOperationException("Invalid boot phase.");
|
||||
_bootPhase = BootPhase.BootRequest;
|
||||
|
||||
// assign the profiler to be the current MiniProfiler for the request
|
||||
// is's already active, starting and all
|
||||
CurrentProfiler = _startupProfiler;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void EndBootRequest()
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
if (_bootPhase != BootPhase.BootRequest)
|
||||
throw new InvalidOperationException("Invalid boot phase.");
|
||||
_bootPhase = BootPhase.Booted;
|
||||
|
||||
_startupProfiler = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new MiniProfiler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is called when WebProfiler calls MiniProfiler.Start() so,
|
||||
/// - as a result of WebRuntime starting the WebProfiler, and
|
||||
/// - assuming profiling is enabled, on every BeginRequest that should be profiled,
|
||||
/// - except for the very first one which is the boot request.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override MiniProfiler Start(string profilerName, MiniProfilerBaseOptions options)
|
||||
{
|
||||
var first = Interlocked.Exchange(ref _first, 1) == 0;
|
||||
if (first == false) return base.Start(profilerName, options);
|
||||
|
||||
_startupProfiler = new MiniProfiler("StartupProfiler", options);
|
||||
CurrentProfiler = _startupProfiler;
|
||||
return _startupProfiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the boot phase.
|
||||
/// </summary>
|
||||
private enum BootPhase
|
||||
{
|
||||
Boot = 0, // boot phase (before the 1st request even begins)
|
||||
BootRequest = 1, // request boot phase (during the 1st request)
|
||||
Booted = 2 // done booting
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<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.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
using Umbraco.Web.Common.Extensions;
|
||||
using Umbraco.Web.Website.AspNetCore;
|
||||
|
||||
|
||||
@@ -21,7 +22,9 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
services.AddUmbracoConfiguration();
|
||||
services.AddUmbracoRequest();
|
||||
services.AddUmbracoWebsite();
|
||||
services.AddUmbracoBackOffice();
|
||||
}
|
||||
@@ -29,6 +32,7 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseUmbracoRequest();
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Net;
|
||||
@@ -11,6 +12,8 @@ namespace Umbraco.Web.AspNet
|
||||
public AspNetUmbracoApplicationLifetime(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
UmbracoApplicationBase.ApplicationInit += ApplicationInit;
|
||||
}
|
||||
|
||||
public bool IsRestarting { get; set; }
|
||||
@@ -30,5 +33,7 @@ namespace Umbraco.Web.AspNet
|
||||
Thread.CurrentPrincipal = null;
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
}
|
||||
|
||||
public event EventHandler ApplicationInit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,20 +56,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
throw new InvalidOperationException("Could not find the super user!");
|
||||
}
|
||||
|
||||
var userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager();
|
||||
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}.");
|
||||
}
|
||||
|
||||
//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());
|
||||
if (!resetResult.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors));
|
||||
}
|
||||
await ResetAdminPassword(user.Password);
|
||||
|
||||
admin.Email = user.Email.Trim();
|
||||
admin.Name = user.Name.Trim();
|
||||
@@ -95,6 +82,26 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task ResetAdminPassword(string clearTextPassword)
|
||||
{
|
||||
var userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager();
|
||||
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}.");
|
||||
}
|
||||
|
||||
//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, clearTextPassword.Trim());
|
||||
if (!resetResult.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a custom view model for this step
|
||||
/// </summary>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -123,6 +123,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Website", "Umbr
|
||||
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.Web.Common", "Umbraco.Web.Common\Umbraco.Web.Common.csproj", "{839D3048-9718-4907-BDE0-7CD63D364383}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -195,6 +197,10 @@ 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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user