diff --git a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
index cb3fd9cf47..d93297ca90 100644
--- a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
@@ -131,8 +131,8 @@ namespace Umbraco.Core.Configuration.Legacy
if (_reservedPaths != null) return _reservedPaths;
var reservedPaths = StaticReservedPaths;
- var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path) && !ConfigurationManager.AppSettings[Constants.AppSettings.Path].IsNullOrWhiteSpace()
- ? ConfigurationManager.AppSettings[Constants.AppSettings.Path]
+ var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.UmbracoPath) && !ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath].IsNullOrWhiteSpace()
+ ? ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath]
: "~/umbraco";
//always add the umbraco path to the list
reservedPaths += umbPath.EnsureEndsWith(',');
@@ -146,12 +146,6 @@ namespace Umbraco.Core.Configuration.Legacy
}
}
- ///
- /// Gets the path to umbraco's root directory (/umbraco by default).
- ///
- /// The path.
- public string Path => ConfigurationManager.AppSettings[Constants.AppSettings.Path];
-
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
///
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
index 68d293d104..4b30813bd5 100644
--- a/src/Umbraco.Configuration/Models/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -30,8 +30,6 @@ namespace Umbraco.Configuration.Models
public string ReservedUrls => _configuration.GetValue(Prefix + "ReservedUrls", StaticReservedUrls);
public string ReservedPaths => _configuration.GetValue(Prefix + "ReservedPaths", StaticReservedPaths);
- public string Path => _configuration.GetValue(Prefix + "Path");
-
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
public string ConfigurationStatus
{
diff --git a/src/Umbraco.Core/Composing/IRuntimeHash.cs b/src/Umbraco.Core/Composing/IRuntimeHash.cs
new file mode 100644
index 0000000000..c2fb829cc6
--- /dev/null
+++ b/src/Umbraco.Core/Composing/IRuntimeHash.cs
@@ -0,0 +1,14 @@
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Used to create a hash value of the current runtime
+ ///
+ ///
+ /// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
+ /// part of the application has changed. This is used to detect if we need to re-type scan.
+ ///
+ public interface IRuntimeHash
+ {
+ string GetHashValue();
+ }
+}
diff --git a/src/Umbraco.Core/Composing/ITypeFinder.cs b/src/Umbraco.Core/Composing/ITypeFinder.cs
index f302976dd6..7ed6084074 100644
--- a/src/Umbraco.Core/Composing/ITypeFinder.cs
+++ b/src/Umbraco.Core/Composing/ITypeFinder.cs
@@ -51,5 +51,14 @@ namespace Umbraco.Core.Composing
Type attributeType,
IEnumerable assemblies,
bool onlyConcreteClasses);
+
+ ///
+ /// Gets a hash value of the current runtime
+ ///
+ ///
+ /// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
+ /// part of the application has changed. This is used to detect if we need to re-type scan.
+ ///
+ string GetRuntimeHash();
}
}
diff --git a/src/Umbraco.Core/Composing/RuntimeHash.cs b/src/Umbraco.Core/Composing/RuntimeHash.cs
new file mode 100644
index 0000000000..16665384c6
--- /dev/null
+++ b/src/Umbraco.Core/Composing/RuntimeHash.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Determines the runtime hash based on file system paths to scan
+ ///
+ public class RuntimeHash : IRuntimeHash
+ {
+ private readonly IProfilingLogger _logger;
+ private readonly RuntimeHashPaths _paths;
+
+ public RuntimeHash(IProfilingLogger logger, RuntimeHashPaths paths)
+ {
+ _logger = logger;
+ _paths = paths;
+ }
+
+
+ public string GetHashValue()
+ {
+ var allPaths = _paths.GetFolders()
+ .Select(x => ((FileSystemInfo) x, false))
+ .Concat(_paths.GetFiles().Select(x => ((FileSystemInfo) x.Key, x.Value)));
+
+ var hash = GetFileHash(allPaths);
+
+ return hash;
+ }
+
+ ///
+ /// Returns a unique hash for a combination of FileInfo objects.
+ ///
+ /// A collection of files.
+ /// The hash.
+ /// Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the
+ /// file properties (false) or the file contents (true).
+ private string GetFileHash(IEnumerable<(FileSystemInfo fileOrFolder, bool scanFileContent)> filesAndFolders)
+ {
+ using (_logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
+ {
+ // get the distinct file infos to hash
+ var uniqInfos = new HashSet();
+ var uniqContent = new HashSet();
+
+ using var generator = new HashGenerator();
+
+ foreach (var (fileOrFolder, scanFileContent) in filesAndFolders)
+ {
+ if (scanFileContent)
+ {
+ // add each unique file's contents to the hash
+ // normalize the content for cr/lf and case-sensitivity
+ if (uniqContent.Add(fileOrFolder.FullName))
+ {
+ if (File.Exists(fileOrFolder.FullName) == false) continue;
+ var content = RemoveCrLf(File.ReadAllText(fileOrFolder.FullName));
+ generator.AddCaseInsensitiveString(content);
+ }
+ }
+ else
+ {
+ // add each unique folder/file to the hash
+ if (uniqInfos.Add(fileOrFolder.FullName))
+ {
+ generator.AddFileSystemItem(fileOrFolder);
+ }
+ }
+ }
+ return generator.GenerateHash();
+ }
+ }
+
+ // fast! (yes, according to benchmarks)
+ private static string RemoveCrLf(string s)
+ {
+ var buffer = new char[s.Length];
+ var count = 0;
+ // ReSharper disable once ForCanBeConvertedToForeach - no!
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] != '\r' && s[i] != '\n')
+ buffer[count++] = s[i];
+ }
+ return new string(buffer, 0, count);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs
new file mode 100644
index 0000000000..8b5af064af
--- /dev/null
+++ b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Paths used to determine the
+ ///
+ public sealed class RuntimeHashPaths
+ {
+ private readonly List _paths = new List();
+ private readonly Dictionary _files = new Dictionary();
+
+ public void AddFolder(DirectoryInfo pathInfo) => _paths.Add(pathInfo);
+ public void AddFile(FileInfo fileInfo, bool scanFileContent = false) => _files.Add(fileInfo, scanFileContent);
+
+ public IEnumerable GetFolders() => _paths;
+ public IReadOnlyDictionary GetFiles() => _files;
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs
index 79fddad1ca..645182d66b 100644
--- a/src/Umbraco.Core/Composing/TypeFinder.cs
+++ b/src/Umbraco.Core/Composing/TypeFinder.cs
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Composing
{
private readonly ILogger _logger;
private readonly IAssemblyProvider _assemblyProvider;
+ private readonly IRuntimeHash _runtimeHash;
private volatile HashSet _localFilteredAssemblyCache;
private readonly object _localFilteredAssemblyCacheLocker = new object();
private readonly List _notifiedLoadExceptionAssemblies = new List();
@@ -25,10 +26,11 @@ namespace Umbraco.Core.Composing
// used for benchmark tests
internal bool QueryWithReferencingAssemblies = true;
- public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, ITypeFinderConfig typeFinderConfig = null)
+ public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, IRuntimeHash runtimeHash, ITypeFinderConfig typeFinderConfig = null)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_assemblyProvider = assemblyProvider;
+ _runtimeHash = runtimeHash;
_assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty();
}
@@ -208,6 +210,9 @@ namespace Umbraco.Core.Composing
return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
}
+ ///
+ public string GetRuntimeHash() => _runtimeHash.GetHashValue();
+
///
/// Returns a Type for the string type name
///
diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs
index 4d8b5c984c..ba6470b060 100644
--- a/src/Umbraco.Core/Composing/TypeLoader.cs
+++ b/src/Umbraco.Core/Composing/TypeLoader.cs
@@ -14,8 +14,6 @@ using File = System.IO.File;
namespace Umbraco.Core.Composing
{
-
-
///
/// Provides methods to find and instantiate types.
///
@@ -29,7 +27,6 @@ namespace Umbraco.Core.Composing
{
private const string CacheKey = "umbraco-types.list";
- private readonly IIOHelper _ioHelper;
private readonly IAppPolicyCache _runtimeCache;
private readonly IProfilingLogger _logger;
@@ -49,30 +46,29 @@ namespace Umbraco.Core.Composing
///
/// Initializes a new instance of the class.
///
- ///
+ ///
///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
///
- public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable assembliesToScan = null)
- : this(ioHelper, typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan)
+ public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable assembliesToScan = null)
+ : this(typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan)
{ }
///
/// Initializes a new instance of the class.
///
- ///
+ ///
///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
/// Whether to detect changes using hashes.
///
- public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable assembliesToScan = null)
+ public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable assembliesToScan = null)
{
TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- _ioHelper = ioHelper;
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_localTempPath = localTempPath;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -124,7 +120,7 @@ namespace Umbraco.Core.Composing
/// This is for unit tests.
///
// internal for tests
- public IEnumerable AssembliesToScan => _assemblies ?? (_assemblies = TypeFinder.AssembliesToScan);
+ public IEnumerable AssembliesToScan => _assemblies ??= TypeFinder.AssembliesToScan;
///
/// Gets the type lists.
@@ -183,19 +179,7 @@ namespace Umbraco.Core.Composing
if (_currentAssembliesHash != null)
return _currentAssembliesHash;
- _currentAssembliesHash = GetFileHash(new List>
- {
- // TODO: Would be nicer to abstract this logic out into IAssemblyHash
-
- // TODO: Use constants from SystemDirectories when we can (once it's ported to netstandard lib)
-
- // the bin folder and everything in it
- new Tuple(new DirectoryInfo(_ioHelper.MapPath("~/bin")), false),
- // the app code folder and everything in it
- new Tuple(new DirectoryInfo(_ioHelper.MapPath("~/App_Code")), false),
- // global.asax (the app domain also monitors this, if it changes will do a full restart)
- new Tuple(new FileInfo(_ioHelper.MapPath("~/global.asax")), false)
- }, _logger);
+ _currentAssembliesHash = TypeFinder.GetRuntimeHash();
return _currentAssembliesHash;
}
@@ -210,92 +194,6 @@ namespace Umbraco.Core.Composing
File.WriteAllText(typesHashFilePath, CurrentAssembliesHash, Encoding.UTF8);
}
- ///
- /// Returns a unique hash for a combination of FileInfo objects.
- ///
- /// A collection of files.
- /// A profiling logger.
- /// The hash.
- /// Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the
- /// file properties (false) or the file contents (true).
- private static string GetFileHash(IEnumerable> filesAndFolders, IProfilingLogger logger)
- {
- using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
- {
- // get the distinct file infos to hash
- var uniqInfos = new HashSet();
- var uniqContent = new HashSet();
- using (var generator = new HashGenerator())
- {
- foreach (var fileOrFolder in filesAndFolders)
- {
- var info = fileOrFolder.Item1;
- if (fileOrFolder.Item2)
- {
- // add each unique file's contents to the hash
- // normalize the content for cr/lf and case-sensitivity
- if (uniqContent.Add(info.FullName))
- {
- if (File.Exists(info.FullName) == false) continue;
- var content = RemoveCrLf(File.ReadAllText(info.FullName));
- generator.AddCaseInsensitiveString(content);
- }
- }
- else
- {
- // add each unique folder/file to the hash
- if (uniqInfos.Add(info.FullName))
- {
- generator.AddFileSystemItem(info);
- }
- }
- }
- return generator.GenerateHash();
- }
- }
- }
-
- // fast! (yes, according to benchmarks)
- private static string RemoveCrLf(string s)
- {
- var buffer = new char[s.Length];
- var count = 0;
- // ReSharper disable once ForCanBeConvertedToForeach - no!
- for (var i = 0; i < s.Length; i++)
- {
- if (s[i] != '\r' && s[i] != '\n')
- buffer[count++] = s[i];
- }
- return new string(buffer, 0, count);
- }
-
- ///
- /// Returns a unique hash for a combination of FileInfo objects.
- ///
- /// A collection of files.
- /// A profiling logger.
- /// The hash.
- // internal for tests
- public static string GetFileHash(IEnumerable filesAndFolders, IProfilingLogger logger)
- {
- using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
- {
- using (var generator = new HashGenerator())
- {
- // get the distinct file infos to hash
- var uniqInfos = new HashSet();
-
- foreach (var fileOrFolder in filesAndFolders)
- {
- if (uniqInfos.Contains(fileOrFolder.FullName)) continue;
- uniqInfos.Add(fileOrFolder.FullName);
- generator.AddFileSystemItem(fileOrFolder);
- }
- return generator.GenerateHash();
- }
- }
- }
-
#endregion
#region Cache
diff --git a/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs b/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs
new file mode 100644
index 0000000000..034af3b80c
--- /dev/null
+++ b/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// A runtime hash this is always different on each app startup
+ ///
+ public sealed class VaryingRuntimeHash : IRuntimeHash
+ {
+ private readonly string _hash;
+
+ public VaryingRuntimeHash()
+ {
+ _hash = DateTime.Now.Ticks.ToString();
+ }
+
+ public string GetHashValue() => _hash;
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
index 3cb211a7a7..434aef6e68 100644
--- a/src/Umbraco.Core/Configuration/IGlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
@@ -20,11 +20,6 @@
/// The reserved paths.
string ReservedPaths { get; }
- ///
- /// Gets the path to umbraco's root directory.
- ///
- string Path { get; }
-
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
///
@@ -61,6 +56,9 @@
/// The version check period in days (0 = never).
int VersionCheckPeriod { get; }
+ ///
+ /// Gets the path to umbraco's root directory.
+ ///
string UmbracoPath { get; }
string UmbracoCssPath { get; }
string UmbracoScriptsPath { get; }
diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs
index c55b4b0314..3551aa1c31 100644
--- a/src/Umbraco.Core/Constants-AppSettings.cs
+++ b/src/Umbraco.Core/Constants-AppSettings.cs
@@ -41,32 +41,27 @@ namespace Umbraco.Core
///
/// Gets the path to umbraco's root directory (/umbraco by default).
///
- public const string Path = "Umbraco.Core.Path";
+ public const string UmbracoPath = "Umbraco.Core.Path";
///
/// The reserved urls from web.config.
///
public const string ReservedUrls = "Umbraco.Core.ReservedUrls";
-
- ///
- /// The path of backoffice.
- ///
- public const string UmbracoPath = "umbracoPath";
-
+
///
/// The path of the stylesheet folder.
///
- public const string UmbracoCssPath = "umbracoCssPath";
+ public const string UmbracoCssPath = "Umbraco.Web.CssPath";
///
/// The path of script folder.
///
- public const string UmbracoScriptsPath = "umbracoScriptsPath";
+ public const string UmbracoScriptsPath = "Umbraco.Core.ScriptsPath";
///
/// The path of media folder.
///
- public const string UmbracoMediaPath = "umbracoMediaPath";
+ public const string UmbracoMediaPath = "Umbraco.Core.MediaPath";
///
/// The reserved paths from web.config
diff --git a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
index b12ffbc138..a7fad8cbea 100644
--- a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
+++ b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
@@ -18,6 +18,21 @@ namespace Umbraco.Core.Hosting
bool IsHosted { get; }
Version IISVersion { get; }
string MapPath(string path);
+
+ ///
+ /// Maps a virtual path to the application's web root
+ ///
+ /// The virtual path. Must start with either ~/ or / else an exception is thrown.
+ /// The absolute web root value. Must start with / else an exception is thrown.
+ ///
+ ///
+ /// This maps the virtual path syntax to the web root. For example when hosting in a virtual directory called "site" and the value "~/pages/test" is passed in, it will
+ /// map to "/site/pages/test" where "/site" is the value of root.
+ ///
+ ///
+ /// If virtualPath does not start with ~/ or /
+ /// If root does not start with /
+ ///
string ToAbsolute(string virtualPath, string root);
}
}
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
index b68c58e91d..33deabf1e8 100644
--- a/src/Umbraco.Core/IO/IOHelper.cs
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -25,7 +25,7 @@ namespace Umbraco.Core.IO
{
get
{
- var path = _globalSettings.Path;
+ var path = _globalSettings.UmbracoPath;
return string.IsNullOrEmpty(path) ? string.Empty : ResolveUrl(path);
}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 5d2a4b4c64..1cedca96dc 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -163,7 +163,7 @@ namespace Umbraco.Core.Runtime
var databaseFactory = GetDatabaseFactory();
// type finder/loader
- var typeLoader = new TypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger);
+ var typeLoader = new TypeLoader(TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger);
// create the composition
composition = new Composition(register, typeLoader, ProfilingLogger, _state, Configs, IOHelper, appCaches);
diff --git a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs
index 7b4322bfac..1571f63500 100644
--- a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs
+++ b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs
@@ -15,16 +15,18 @@ namespace Umbraco.Tests.Benchmarks
[Benchmark(Baseline = true)]
public void WithGetReferencingAssembliesCheck()
{
- var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
var found = typeFinder1.FindClassesOfType().Count();
}
[Benchmark]
public void WithoutGetReferencingAssembliesCheck()
{
- var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
typeFinder2.QueryWithReferencingAssemblies = false;
var found = typeFinder2.FindClassesOfType().Count();
}
+
+
}
}
diff --git a/src/Umbraco.Tests.Common/SettingsForTests.cs b/src/Umbraco.Tests.Common/SettingsForTests.cs
index f7427009ba..c3ba47e61b 100644
--- a/src/Umbraco.Tests.Common/SettingsForTests.cs
+++ b/src/Umbraco.Tests.Common/SettingsForTests.cs
@@ -24,7 +24,6 @@ namespace Umbraco.Tests.Common
settings.ConfigurationStatus == semanticVersion.ToSemanticString() &&
settings.UseHttps == false &&
settings.HideTopLevelNodeFromPath == false &&
- settings.Path == "~/umbraco" &&
settings.TimeOutInMinutes == 20 &&
settings.DefaultUILanguage == "en" &&
settings.ReservedPaths == (GlobalSettings.StaticReservedPaths + "~/umbraco") &&
diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs
index b14bd5fd5d..42b1e6c0dd 100644
--- a/src/Umbraco.Tests.Common/TestHelperBase.cs
+++ b/src/Umbraco.Tests.Common/TestHelperBase.cs
@@ -36,14 +36,14 @@ namespace Umbraco.Tests.Common
{
SettingsForTests = new SettingsForTests();
MainDom = new SimpleMainDom();
- _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly));
+ _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly), new VaryingRuntimeHash());
}
public ITypeFinder GetTypeFinder() => _typeFinder;
public TypeLoader GetMockedTypeLoader()
{
- return new TypeLoader(IOHelper, Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
+ return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
}
public Configs GetConfigs() => GetConfigsFactory().Create();
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
index e756ee5062..d46c01acba 100644
--- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
@@ -106,8 +106,7 @@ namespace Umbraco.Tests.Integration.Implementations
public override IHostingEnvironment GetHostingEnvironment()
=> _hostingEnvironment ??= new TestHostingEnvironment(
SettingsForTests.GetDefaultHostingSettings(),
- _hostEnvironment,
- _httpContextAccessor);
+ _hostEnvironment);
public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _hostingLifetime;
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
index 4a54dd2823..6430291bc2 100644
--- a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
@@ -8,8 +8,8 @@ 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)
+ public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment)
+ : base(hostingSettings, webHostEnvironment)
{
}
diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs
index cb8da6e23d..807c12973c 100644
--- a/src/Umbraco.Tests/Components/ComponentTests.cs
+++ b/src/Umbraco.Tests/Components/ComponentTests.cs
@@ -56,7 +56,7 @@ namespace Umbraco.Tests.Components
private static TypeLoader MockTypeLoader()
{
var ioHelper = TestHelper.IOHelper;
- return new TypeLoader(ioHelper, Mock.Of(), Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
+ return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
}
public static IRuntimeState MockRuntimeState(RuntimeLevel level)
@@ -372,7 +372,7 @@ namespace Umbraco.Tests.Components
{
var ioHelper = TestHelper.IOHelper;
var typeFinder = TestHelper.GetTypeFinder();
- var typeLoader = new TypeLoader(ioHelper, typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
+ var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
var register = MockRegister();
var composition = new Composition(register, typeLoader, Mock.Of(),
diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
index 6c5ccd5510..1977a5dfc1 100644
--- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs
+++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
@@ -24,7 +24,7 @@ namespace Umbraco.Tests.Composing
var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
- TypeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan);
+ TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan);
}
[TearDown]
diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests/Composing/CompositionTests.cs
index ce3cdfac17..380511eaaa 100644
--- a/src/Umbraco.Tests/Composing/CompositionTests.cs
+++ b/src/Umbraco.Tests/Composing/CompositionTests.cs
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Composing
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
- var typeLoader = new TypeLoader(ioHelper, typeFinder, Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger);
+ var typeLoader = new TypeLoader(typeFinder, Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of(), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache);
// create the factory, ensure it is the mocked factory
diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
index 3bdfd09752..aad8337d00 100644
--- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
@@ -57,7 +57,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void Find_Class_Of_Type_With_Attribute()
{
- var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies);
Assert.AreEqual(2, typesFound.Count());
}
@@ -65,7 +65,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void Find_Classes_With_Attribute()
{
- var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
var typesFound = typeFinder.FindClassesWithAttribute(_assemblies);
Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree]
diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
index d0181563a8..980878d6f2 100644
--- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Composing
{
// this ensures it's reset
var typeFinder = TestHelper.GetTypeFinder();
- _typeLoader = new TypeLoader(TestHelper.IOHelper, typeFinder, NoAppCache.Instance,
+ _typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance,
new DirectoryInfo(TestHelper.IOHelper.MapPath("~/App_Data/TEMP")),
new ProfilingLogger(Mock.Of(), Mock.Of()), false,
@@ -217,7 +217,7 @@ AnotherContentFinder
}
[Test]
- public void Get_Plugins_Hash()
+ public void Get_Plugins_Hash_With_Hash_Generator()
{
//Arrange
var dir = PrepareFolder();
@@ -244,16 +244,16 @@ AnotherContentFinder
var list3 = new[] { f1, f3, f5, f7 };
//Act
- var hash1 = TypeLoader.GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of()));
- var hash2 = TypeLoader.GetFileHash(list2, new ProfilingLogger(Mock.Of(), Mock.Of()));
- var hash3 = TypeLoader.GetFileHash(list3, new ProfilingLogger(Mock.Of(), Mock.Of()));
+ var hash1 = GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of()));
+ var hash2 = GetFileHash(list2, new ProfilingLogger(Mock.Of(), Mock.Of()));
+ var hash3 = GetFileHash(list3, new ProfilingLogger(Mock.Of(), Mock.Of()));
//Assert
Assert.AreNotEqual(hash1, hash2);
Assert.AreNotEqual(hash1, hash3);
Assert.AreNotEqual(hash2, hash3);
- Assert.AreEqual(hash1, TypeLoader.GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of())));
+ Assert.AreEqual(hash1, GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of())));
}
[Test]
@@ -316,5 +316,32 @@ AnotherContentFinder
}
+
+ ///
+ /// Returns a unique hash for a combination of FileInfo objects.
+ ///
+ /// A collection of files.
+ /// A profiling logger.
+ /// The hash.
+ // internal for tests
+ private static string GetFileHash(IEnumerable filesAndFolders, IProfilingLogger logger)
+ {
+ using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
+ {
+ using (var generator = new HashGenerator())
+ {
+ // get the distinct file infos to hash
+ var uniqInfos = new HashSet();
+
+ foreach (var fileOrFolder in filesAndFolders)
+ {
+ if (uniqInfos.Contains(fileOrFolder.FullName)) continue;
+ uniqInfos.Add(fileOrFolder.FullName);
+ generator.AddFileSystemItem(fileOrFolder);
+ }
+ return generator.GenerateHash();
+ }
+ }
+ }
}
}
diff --git a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
index b171199e25..a1f1e6a66d 100644
--- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
+++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Configurations
var ioHelper = new IOHelper(TestHelper.GetHostingEnvironment(), globalSettings);
var globalSettingsMock = Mock.Get(globalSettings);
- globalSettingsMock.Setup(x => x.Path).Returns(() => path);
+ globalSettingsMock.Setup(x => x.UmbracoPath).Returns(() => path);
ioHelper.Root = rootPath;
Assert.AreEqual(outcome, ioHelper.GetUmbracoMvcAreaNoCache());
diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs
index 06a53db4ff..756f452f71 100644
--- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs
+++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs
@@ -50,7 +50,7 @@ namespace Umbraco.Tests.PublishedContent
{
var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment);
- return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false,
+ return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false,
// this is so the model factory looks into the test assembly
baseLoader.AssembliesToScan
.Union(new[] {typeof(PublishedContentMoreTests).Assembly})
diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
index 2667848c57..013ae712cc 100644
--- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
@@ -99,7 +99,7 @@ namespace Umbraco.Tests.PublishedContent
{
var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment);
- return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false,
+ return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false,
// this is so the model factory looks into the test assembly
baseLoader.AssembliesToScan
.Union(new[] { typeof(PublishedContentTests).Assembly })
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 913fc59ad6..1b6526c24b 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -69,7 +69,7 @@ namespace Umbraco.Tests.Runtimes
var databaseFactory = new UmbracoDatabaseFactory(logger,globalSettings, connectionStrings, new Lazy(() => factory.GetInstance()), TestHelper.DbProviderFactoryCreator);
var ioHelper = TestHelper.IOHelper;
var hostingEnvironment = Mock.Of();
- var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
+ var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
var mainDom = new SimpleMainDom();
var umbracoVersion = TestHelper.GetUmbracoVersion();
var backOfficeInfo = TestHelper.GetBackOfficeInfo();
@@ -262,7 +262,7 @@ namespace Umbraco.Tests.Runtimes
var databaseFactory = Mock.Of();
var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
- var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
+ var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
var runtimeState = Mock.Of();
var hostingEnvironment = Mock.Of();
var backOfficeInfo = TestHelper.GetBackOfficeInfo();
diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
index e035eaa807..bd7df73172 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
@@ -39,7 +39,7 @@ namespace Umbraco.Tests.TestHelpers
var ioHelper = TestHelper.IOHelper;
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
var typeFinder = TestHelper.GetTypeFinder();
- var typeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance,
+ var typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance,
new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")),
logger,
false);
diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
index e982b5c0d1..cc61c84abd 100644
--- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
@@ -253,7 +253,7 @@ namespace Umbraco.Tests.TestHelpers
TestHelper.DbProviderFactoryCreator);
}
- typeFinder ??= new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ typeFinder ??= new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
fileSystems ??= new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings());
var coreDebug = TestHelper.CoreDebugSettings;
var mediaFileSystem = Mock.Of();
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index 880ae62e4a..56f0534cf4 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -173,7 +173,7 @@ namespace Umbraco.Tests.Testing
var proflogger = new ProfilingLogger(logger, profiler);
IOHelper = TestHelper.IOHelper;
- TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash());
var appCaches = GetAppCaches();
var globalSettings = TestHelpers.SettingsForTests.GetDefaultGlobalSettings();
var settings = TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings();
@@ -376,7 +376,7 @@ namespace Umbraco.Tests.Testing
switch (option)
{
case UmbracoTestOptions.TypeLoader.Default:
- return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment));
+ return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(typeFinder, runtimeCache, logger, hostingEnvironment));
case UmbracoTestOptions.TypeLoader.PerFixture:
return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment));
case UmbracoTestOptions.TypeLoader.PerTest:
@@ -388,13 +388,13 @@ namespace Umbraco.Tests.Testing
protected virtual TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment)
{
- return CreateCommonTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment);
+ return CreateCommonTypeLoader(typeFinder, runtimeCache, logger, hostingEnvironment);
}
// common to all tests = cannot be overriden
- private static TypeLoader CreateCommonTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment)
+ private static TypeLoader CreateCommonTypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment)
{
- return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false, new[]
+ return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false, new[]
{
Assembly.Load("Umbraco.Core"),
Assembly.Load("Umbraco.Web"),
diff --git a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
index 62d7e941d7..b17943e63e 100644
--- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
+++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
@@ -33,7 +33,6 @@ namespace Umbraco.Tests.Web
container
.Setup(x => x.GetInstance(typeof(TypeLoader)))
.Returns(new TypeLoader(
- ioHelper,
typeFinder,
NoAppCache.Instance,
new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")),
diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
index d8f8fc1aed..f82144f9a7 100644
--- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Data.Common;
+using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@@ -100,10 +101,6 @@ namespace Umbraco.Web.Common.Extensions
var globalSettings = configs.Global();
var umbracoVersion = new UmbracoVersion(globalSettings);
- // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
- // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
- var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly));
-
var coreRuntime = GetCoreRuntime(
configs,
umbracoVersion,
@@ -112,13 +109,23 @@ namespace Umbraco.Web.Common.Extensions
profiler,
hostingEnvironment,
backOfficeInfo,
- typeFinder);
+ CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly));
factory = coreRuntime.Configure(container);
return services;
}
+ private static ITypeFinder CreateTypeFinder(ILogger logger, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly)
+ {
+ // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
+ // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
+ var runtimeHashPaths = new RuntimeHashPaths();
+ runtimeHashPaths.AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin")));
+ var runtimeHash = new RuntimeHash(new ProfilingLogger(logger, profiler), runtimeHashPaths);
+ return new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash);
+ }
+
private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger,
IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
ITypeFinder typeFinder)
@@ -161,7 +168,7 @@ namespace Umbraco.Web.Common.Extensions
var coreDebug = configs.CoreDebug();
var globalSettings = configs.Global();
- hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor);
+ hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment);
ioHelper = new IOHelper(hostingEnvironment, globalSettings);
logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment,
new AspNetCoreSessionIdResolver(httpContextAccessor),
diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs
index 748f3239e8..284b8e91da 100644
--- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs
+++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs
@@ -9,7 +9,8 @@ namespace Umbraco.Web.Common.RuntimeMinification
{
public void Compose(Composition composition)
{
- composition.Register(Core.Composing.Lifetime.Scope);
+ composition.RegisterUnique();
+ composition.RegisterUnique();
}
}
}
diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs
new file mode 100644
index 0000000000..c46a948bc2
--- /dev/null
+++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs
@@ -0,0 +1,29 @@
+using System;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Smidge;
+
+namespace Umbraco.Web.Common.RuntimeMinification
+{
+ // work around for SmidgeHelper being request/scope lifetime
+ public sealed class SmidgeHelperAccessor
+ {
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ public SmidgeHelperAccessor(IHttpContextAccessor httpContextAccessor)
+ {
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ public SmidgeHelper SmidgeHelper
+ {
+ get
+ {
+ var httpContext = _httpContextAccessor.HttpContext;
+ if (httpContext == null)
+ throw new InvalidOperationException($"Cannot get a {nameof(SmidgeHelper)} instance since there is no current http request");
+ return httpContext.RequestServices.GetService();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
index c279fd0280..b73a8d38bd 100644
--- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
+++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
@@ -22,15 +22,15 @@ namespace Umbraco.Web.Common.RuntimeMinification
private readonly ISmidgeConfig _smidgeConfig;
private readonly IConfigManipulator _configManipulator;
private readonly PreProcessPipelineFactory _preProcessPipelineFactory;
- private readonly BundleManager _bundles;
- private readonly SmidgeHelper _smidge;
+ private readonly IBundleManager _bundles;
+ private readonly SmidgeHelperAccessor _smidge;
private PreProcessPipeline _jsPipeline;
private PreProcessPipeline _cssPipeline;
public SmidgeRuntimeMinifier(
- BundleManager bundles,
- SmidgeHelper smidge,
+ IBundleManager bundles,
+ SmidgeHelperAccessor smidge,
PreProcessPipelineFactory preProcessPipelineFactory,
IHostingEnvironment hostingEnvironment,
ISmidgeConfig smidgeConfig,
@@ -65,7 +65,7 @@ namespace Umbraco.Web.Common.RuntimeMinification
// affect this or vice versa.
}
- public string RenderCssHere(string bundleName) => _smidge.CssHereAsync(bundleName, _hostingEnvironment.IsDebugMode).ToString();
+ public string RenderCssHere(string bundleName) => _smidge.SmidgeHelper.CssHereAsync(bundleName, _hostingEnvironment.IsDebugMode).ToString();
public void CreateJsBundle(string bundleName, params string[] filePaths)
{
@@ -82,9 +82,9 @@ namespace Umbraco.Web.Common.RuntimeMinification
// affect this or vice versa.
}
- public string RenderJsHere(string bundleName) => _smidge.JsHereAsync(bundleName, _hostingEnvironment.IsDebugMode).ToString();
+ public string RenderJsHere(string bundleName) => _smidge.SmidgeHelper.JsHereAsync(bundleName, _hostingEnvironment.IsDebugMode).ToString();
- public async Task> GetAssetPathsAsync(string bundleName) => await _smidge.GenerateJsUrlsAsync(bundleName, _hostingEnvironment.IsDebugMode);
+ public async Task> GetAssetPathsAsync(string bundleName) => await _smidge.SmidgeHelper.GenerateJsUrlsAsync(bundleName, _hostingEnvironment.IsDebugMode);
public async Task MinifyAsync(string fileContent, AssetType assetType)
{
diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs
index 51ab151463..75b2d6f48e 100644
--- a/src/Umbraco.Web.UI.NetCore/Startup.cs
+++ b/src/Umbraco.Web.UI.NetCore/Startup.cs
@@ -21,7 +21,7 @@ namespace Umbraco.Web.UI.BackOffice
{
public class Startup
{
- private readonly IWebHostEnvironment _webHostEnvironment;
+ private readonly IWebHostEnvironment _env;
private readonly IConfiguration _config;
///
@@ -34,7 +34,7 @@ namespace Umbraco.Web.UI.BackOffice
///
public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config)
{
- _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
+ _env = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
_config = config ?? throw new ArgumentNullException(nameof(config));
}
@@ -44,7 +44,7 @@ namespace Umbraco.Web.UI.BackOffice
{
services.AddUmbracoConfiguration(_config);
services.AddUmbracoRuntimeMinifier(_config);
- services.AddUmbracoCore(_webHostEnvironment, out var factory);
+ services.AddUmbracoCore(_env, out var factory);
services.AddUmbracoWebsite();
services.AddMvc();
@@ -66,12 +66,12 @@ 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)
+ public void Configure(IApplicationBuilder app)
{
// app.UseMiniProfiler();
app.UseUmbracoRequest();
- if (env.IsDevelopment())
+ if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs
index 0963ad3c07..5e1c3cd954 100644
--- a/src/Umbraco.Web/UmbracoApplicationBase.cs
+++ b/src/Umbraco.Web/UmbracoApplicationBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Reflection;
using System.Threading;
using System.Web;
@@ -80,9 +81,18 @@ namespace Umbraco.Web
///
///
protected virtual ITypeFinder GetTypeFinder()
+ {
// TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
// this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
- => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
+ var runtimeHashPaths = new RuntimeHashPaths();
+ // the bin folder and everything in it
+ runtimeHashPaths.AddFolder(new DirectoryInfo(Current.IOHelper.MapPath("~/bin")));
+ // the app code folder and everything in it
+ runtimeHashPaths.AddFile(new FileInfo(Current.IOHelper.MapPath("~/App_Code")));
+ // global.asax (the app domain also monitors this, if it changes will do a full restart)
+ runtimeHashPaths.AddFile(new FileInfo(Current.IOHelper.MapPath("~/global.asax")));
+ var runtimeHash = new RuntimeHash(new ProfilingLogger(Current.Logger, Current.Profiler), runtimeHashPaths);
+ return new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
// GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website
// in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since
// the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly()
@@ -94,7 +104,8 @@ namespace Umbraco.Web
// assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one.
// For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are
// getting rid of netframework.
- Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()));
+ Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()), runtimeHash);
+ }
///
/// Gets a runtime.