From d3232a09fbfcbebcb1abf86a43c0c06f09c3dd34 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Oct 2017 11:47:25 +1100 Subject: [PATCH 1/2] U4-10503 Umbraco plugins cache files should be stored in the same local temp location as the umbraco xml cache file (cherry picked from commit 7b3f7f4ad47528540143f7598b22d34ee5a1962d) --- .../Configuration/GlobalSettings.cs | 35 ++++++++++++++----- ...ntentXmlStorage.cs => LocalTempStorage.cs} | 2 +- src/Umbraco.Core/IO/SystemFiles.cs | 8 ++--- src/Umbraco.Core/PluginManager.cs | 22 ++++++++++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- 5 files changed, 51 insertions(+), 18 deletions(-) rename src/Umbraco.Core/Configuration/{ContentXmlStorage.cs => LocalTempStorage.cs} (75%) diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index acbf0065c0..429d9f0ef9 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -518,24 +518,41 @@ namespace Umbraco.Core.Configuration internal static bool ContentCacheXmlStoredInCodeGen { - get { return ContentCacheXmlStorageLocation == ContentXmlStorage.AspNetTemp; } + get { return LocalTempStorageLocation == LocalTempStorage.AspNetTemp; } } - - internal static ContentXmlStorage ContentCacheXmlStorageLocation + + /// + /// This is the location type to store temporary files such as cache files or other localized files for a given machine + /// + /// + /// Currently used for the xml cache file and the plugin cache files + /// + internal static LocalTempStorage LocalTempStorageLocation { get - { + { + //there's a bunch of backwards compat config checks here.... + + //This is the current one + if (ConfigurationManager.AppSettings.ContainsKey("umbracoLocalTempStorage")) + { + return Enum.Parse(ConfigurationManager.AppSettings["umbracoLocalTempStorage"]); + } + + //This one is old if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLStorage")) { - return Enum.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]); - } + return Enum.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]); + } + + //This one is older if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp")) { return bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"]) - ? ContentXmlStorage.AspNetTemp - : ContentXmlStorage.Default; + ? LocalTempStorage.AspNetTemp + : LocalTempStorage.Default; } - return ContentXmlStorage.Default; + return LocalTempStorage.Default; } } diff --git a/src/Umbraco.Core/Configuration/ContentXmlStorage.cs b/src/Umbraco.Core/Configuration/LocalTempStorage.cs similarity index 75% rename from src/Umbraco.Core/Configuration/ContentXmlStorage.cs rename to src/Umbraco.Core/Configuration/LocalTempStorage.cs index 7cbbc70675..d41f7d1925 100644 --- a/src/Umbraco.Core/Configuration/ContentXmlStorage.cs +++ b/src/Umbraco.Core/Configuration/LocalTempStorage.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration { - internal enum ContentXmlStorage + internal enum LocalTempStorage { Default, AspNetTemp, diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 437ddd3ef7..412849d5b0 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -73,11 +73,11 @@ namespace Umbraco.Core.IO { get { - switch (GlobalSettings.ContentCacheXmlStorageLocation) + switch (GlobalSettings.LocalTempStorageLocation) { - case ContentXmlStorage.AspNetTemp: + case LocalTempStorage.AspNetTemp: return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config"); - case ContentXmlStorage.EnvironmentTemp: + case LocalTempStorage.EnvironmentTemp: var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml", //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back @@ -85,7 +85,7 @@ namespace Umbraco.Core.IO // utilizing an old path appDomainHash); return Path.Combine(cachePath, "umbraco.config"); - case ContentXmlStorage.Default: + case LocalTempStorage.Default: return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config"); default: throw new ArgumentOutOfRangeException(); diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index f90163d181..b6a72f74cf 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading; +using System.Web; using System.Web.Compilation; using Umbraco.Core.Cache; using Umbraco.Core.IO; @@ -15,6 +16,7 @@ using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Profiling; using Umbraco.Core.PropertyEditors; using umbraco.interfaces; +using Umbraco.Core.Configuration; using File = System.IO.File; namespace Umbraco.Core @@ -426,9 +428,23 @@ namespace Umbraco.Core } private string GetPluginListFilePath() - { - var filename = "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"; - return Path.Combine(_tempFolder, filename); + { + switch (GlobalSettings.LocalTempStorageLocation) + { + case LocalTempStorage.AspNetTemp: + return Path.Combine(HttpRuntime.CodegenDir, "umbraco-plugins.list"); + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoPlugins", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + return Path.Combine(cachePath, "umbraco-plugins.list"); + case LocalTempStorage.Default: + default: + return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"); + } } private string GetPluginHashFilePath() diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 37867fce80..3dc90f2d41 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -200,7 +200,7 @@ - + From f0b5c831f13725afe32a67bab109e935d9988d40 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 25 Oct 2017 13:59:11 +0200 Subject: [PATCH 2/2] Manually applied all changes for U4-10503 Umbraco plugins cache files should be stored in the same local temp location as the umbraco xml cache file --- src/Umbraco.Core/PluginManager.cs | 205 ++++++++++-------- .../Sync/DatabaseServerMessenger.cs | 51 +++-- src/Umbraco.Tests/Models/ContentTests.cs | 2 +- .../TestHelpers/BaseUmbracoApplicationTest.cs | 62 ++---- 4 files changed, 175 insertions(+), 145 deletions(-) diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index b6a72f74cf..384478e3cc 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -41,7 +41,8 @@ namespace Umbraco.Core private readonly IServiceProvider _serviceProvider; private readonly IRuntimeCacheProvider _runtimeCache; private readonly ProfilingLogger _logger; - private readonly string _tempFolder; + private readonly Lazy _pluginListFilePath = new Lazy(GetPluginListFilePath); + private readonly Lazy _pluginHashFilePath = new Lazy(GetPluginHashFilePath); private readonly object _typesLock = new object(); private readonly Dictionary _types = new Dictionary(); @@ -66,15 +67,8 @@ namespace Umbraco.Core _serviceProvider = serviceProvider; _runtimeCache = runtimeCache; - _logger = logger; - - // the temp folder where the cache file lives - _tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache"); - if (Directory.Exists(_tempFolder) == false) - Directory.CreateDirectory(_tempFolder); - - var pluginListFile = GetPluginListFilePath(); - + _logger = logger; + if (detectChanges) { //first check if the cached hash is string.Empty, if it is then we need @@ -86,7 +80,8 @@ namespace Umbraco.Core // if the hash has changed, clear out the persisted list no matter what, this will force // rescanning of all plugin types including lazy ones. // http://issues.umbraco.org/issue/U4-4789 - File.Delete(pluginListFile); + if (File.Exists(_pluginListFilePath.Value)) + File.Delete(_pluginListFilePath.Value); WriteCachePluginsHash(); } @@ -96,7 +91,8 @@ namespace Umbraco.Core // if the hash has changed, clear out the persisted list no matter what, this will force // rescanning of all plugin types including lazy ones. // http://issues.umbraco.org/issue/U4-4789 - File.Delete(pluginListFile); + if (File.Exists(_pluginListFilePath.Value)) + File.Delete(_pluginListFilePath.Value); // always set to true if we're not detecting (generally only for testing) RequiresRescanning = true; @@ -188,12 +184,11 @@ namespace Umbraco.Core get { if (_cachedAssembliesHash != null) - return _cachedAssembliesHash; + return _cachedAssembliesHash; + + if (File.Exists(_pluginHashFilePath.Value) == false) return string.Empty; - var filePath = GetPluginHashFilePath(); - if (File.Exists(filePath) == false) return string.Empty; - - var hash = File.ReadAllText(filePath, Encoding.UTF8); + var hash = File.ReadAllText(_pluginHashFilePath.Value, Encoding.UTF8); _cachedAssembliesHash = hash; return _cachedAssembliesHash; @@ -211,8 +206,8 @@ namespace Umbraco.Core if (_currentAssembliesHash != null) return _currentAssembliesHash; - _currentAssembliesHash = GetFileHash(new List> - { + _currentAssembliesHash = GetFileHash(new List> + { // the bin folder and everything in it new Tuple(new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Bin)), false), // the app code folder and everything in it @@ -220,8 +215,8 @@ namespace Umbraco.Core // 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), // trees.config - use the contents to create the hash since this gets resaved on every app startup! - new Tuple(new FileInfo(IOHelper.MapPath(SystemDirectories.Config + "/trees.config")), true) - }, _logger); + new Tuple(new FileInfo(IOHelper.MapPath(SystemDirectories.Config + "/trees.config")), true) + }, _logger); return _currentAssembliesHash; } @@ -231,9 +226,8 @@ namespace Umbraco.Core /// Writes the assembly hash file. /// private void WriteCachePluginsHash() - { - var filePath = GetPluginHashFilePath(); - File.WriteAllText(filePath, CurrentAssembliesHash.ToString(), Encoding.UTF8); + { + File.WriteAllText(_pluginHashFilePath.Value, CurrentAssembliesHash, Encoding.UTF8); } /// @@ -276,7 +270,7 @@ namespace Umbraco.Core } } } - return generator.GenerateHash(); + return generator.GenerateHash(); } } } @@ -316,7 +310,7 @@ namespace Umbraco.Core uniqInfos.Add(fileOrFolder.FullName); generator.AddFileSystemItem(fileOrFolder); } - return generator.GenerateHash(); + return generator.GenerateHash(); } } } @@ -349,12 +343,11 @@ namespace Umbraco.Core { return ReadCache(); } - catch + catch (Exception ex) { try { - var filePath = GetPluginListFilePath(); - File.Delete(filePath); + File.Delete(_pluginListFilePath.Value); } catch { @@ -367,13 +360,12 @@ namespace Umbraco.Core internal Dictionary, IEnumerable> ReadCache() { - var cache = new Dictionary, IEnumerable>(); - - var filePath = GetPluginListFilePath(); - if (File.Exists(filePath) == false) + var cache = new Dictionary, IEnumerable>(); + + if (File.Exists(_pluginListFilePath.Value) == false) return cache; - using (var stream = GetFileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, ListFileOpenReadTimeout)) + using (var stream = GetFileStream(_pluginListFilePath.Value, FileMode.Open, FileAccess.Read, FileShare.Read, ListFileOpenReadTimeout)) using (var reader = new StreamReader(stream)) { while (true) @@ -416,52 +408,86 @@ namespace Umbraco.Core /// Generally only used for resetting cache, for example during the install process. public void ClearPluginCache() { - var path = GetPluginListFilePath(); - if (File.Exists(path)) - File.Delete(path); - - path = GetPluginHashFilePath(); - if (File.Exists(path)) - File.Delete(path); + if (File.Exists(_pluginListFilePath.Value)) + File.Delete(_pluginListFilePath.Value); + + if (File.Exists(_pluginHashFilePath.Value)) + File.Delete(_pluginHashFilePath.Value); _runtimeCache.ClearCacheItem(CacheKey); } - private string GetPluginListFilePath() - { + private static string GetPluginListFilePath() + { + string pluginListFilePath; switch (GlobalSettings.LocalTempStorageLocation) - { + { case LocalTempStorage.AspNetTemp: - return Path.Combine(HttpRuntime.CodegenDir, "umbraco-plugins.list"); + pluginListFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.list"); + break; case LocalTempStorage.EnvironmentTemp: var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoPlugins", - //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // utilizing an old path + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path appDomainHash); - return Path.Combine(cachePath, "umbraco-plugins.list"); - case LocalTempStorage.Default: + pluginListFilePath = Path.Combine(cachePath, "umbraco-plugins.list"); + break; + case LocalTempStorage.Default: default: - return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"); + var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache"); + pluginListFilePath = Path.Combine(tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"); + break; } + + //ensure the folder exists + var folder = Path.GetDirectoryName(pluginListFilePath); + if (folder == null) + throw new InvalidOperationException("The folder could not be determined for the file " + pluginListFilePath); + if (Directory.Exists(folder) == false) + Directory.CreateDirectory(folder); + + return pluginListFilePath; } - private string GetPluginHashFilePath() + private static string GetPluginHashFilePath() { - var filename = "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash"; - return Path.Combine(_tempFolder, filename); + string pluginHashFilePath; + switch (GlobalSettings.LocalTempStorageLocation) + { + case LocalTempStorage.AspNetTemp: + pluginHashFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.hash"); + break; + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + pluginHashFilePath = Path.Combine(cachePath, "umbraco-plugins.hash"); + break; + case LocalTempStorage.Default: + default: + var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache"); + pluginHashFilePath = Path.Combine(tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash"); + break; + } + + //ensure the folder exists + var folder = Path.GetDirectoryName(pluginHashFilePath); + if (folder == null) + throw new InvalidOperationException("The folder could not be determined for the file " + pluginHashFilePath); + if (Directory.Exists(folder) == false) + Directory.CreateDirectory(folder); + + return pluginHashFilePath; } internal void WriteCache() { - // be absolutely sure - if (Directory.Exists(_tempFolder) == false) - Directory.CreateDirectory(_tempFolder); - - var filePath = GetPluginListFilePath(); - - using (var stream = GetFileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout)) + using (var stream = GetFileStream(_pluginListFilePath.Value, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout)) using (var writer = new StreamWriter(stream)) { foreach (var typeList in _types.Values) @@ -477,8 +503,7 @@ namespace Umbraco.Core internal void UpdateCache() { - // note - // at the moment we write the cache to disk every time we update it. ideally we defer the writing + // TODO: at the moment we write the cache to disk every time we update it. ideally we defer the writing // since all the updates are going to happen in a row when Umbraco starts. that being said, the // file is small enough, so it is not a priority. WriteCache(); @@ -491,13 +516,13 @@ namespace Umbraco.Core while (true) { try - { + { return new FileStream(path, fileMode, fileAccess, fileShare); } - catch + catch (Exception ex) { if (--attempts == 0) - throw; + throw; LogHelper.Debug(string.Format("Attempted to get filestream for file {0} failed, {1} attempts left, pausing for {2} milliseconds", path, attempts, pauseMilliseconds)); Thread.Sleep(pauseMilliseconds); @@ -576,7 +601,7 @@ namespace Umbraco.Core if (cache == false || typeof(IDiscoverable).IsAssignableFrom(typeof(T)) == false) { return ResolveTypesInternal( - typeof (T), null, + typeof(T), null, () => TypeFinder.FindClassesOfType(specificAssemblies ?? AssembliesToScan), cache); } @@ -585,14 +610,14 @@ namespace Umbraco.Core // filter the cached discovered types (and cache the result) var discovered = ResolveTypesInternal( - typeof (IDiscoverable), null, + typeof(IDiscoverable), null, () => TypeFinder.FindClassesOfType(AssembliesToScan), true); return ResolveTypesInternal( - typeof (T), null, + typeof(T), null, () => discovered - .Where(x => typeof (T).IsAssignableFrom(x)), + .Where(x => typeof(T).IsAssignableFrom(x)), true); } @@ -615,7 +640,7 @@ namespace Umbraco.Core if (cache == false || typeof(IDiscoverable).IsAssignableFrom(typeof(T)) == false) { return ResolveTypesInternal( - typeof (T), typeof (TAttribute), + typeof(T), typeof(TAttribute), () => TypeFinder.FindClassesOfTypeWithAttribute(specificAssemblies ?? AssembliesToScan), cache); } @@ -624,12 +649,12 @@ namespace Umbraco.Core // filter the cached discovered types (and cache the result) var discovered = ResolveTypesInternal( - typeof (IDiscoverable), null, + typeof(IDiscoverable), null, () => TypeFinder.FindClassesOfType(AssembliesToScan), true); return ResolveTypesInternal( - typeof (T), typeof (TAttribute), + typeof(T), typeof(TAttribute), () => discovered .Where(x => typeof(T).IsAssignableFrom(x)) .Where(x => x.GetCustomAttributes(false).Any()), @@ -651,7 +676,7 @@ namespace Umbraco.Core cache &= specificAssemblies == null; return ResolveTypesInternal( - typeof (object), typeof (TAttribute), + typeof(object), typeof(TAttribute), () => TypeFinder.FindClassesWithAttribute(specificAssemblies ?? AssembliesToScan), cache); } @@ -668,14 +693,14 @@ namespace Umbraco.Core var name = ResolvedName(baseType, attributeType); - lock (_typesLock) - using (_logger.TraceDuration( - "Resolving " + name, - "Resolved " + name)) // cannot contain typesFound.Count as it's evaluated before the find - { - // resolve within a lock & timer - return ResolveTypesInternalLocked(baseType, attributeType, finder, cache); - } + lock (_typesLock) + using (_logger.TraceDuration( + "Resolving " + name, + "Resolved " + name)) // cannot contain typesFound.Count as it's evaluated before the find + { + // resolve within a lock & timer + return ResolveTypesInternalLocked(baseType, attributeType, finder, cache); + } } private static string ResolvedName(Type baseType, Type attributeType) @@ -707,7 +732,7 @@ namespace Umbraco.Core // else proceed, typeList = new TypeList(baseType, attributeType); - var scan = RequiresRescanning || File.Exists(GetPluginListFilePath()) == false; + var scan = RequiresRescanning || File.Exists(_pluginListFilePath.Value) == false; if (scan) { @@ -811,7 +836,7 @@ namespace Umbraco.Core public TypeListKey(Type baseType, Type attributeType) { - BaseType = baseType ?? typeof (object); + BaseType = baseType ?? typeof(object); AttributeType = attributeType; } @@ -829,7 +854,7 @@ namespace Umbraco.Core var hash = 5381; hash = ((hash << 5) + hash) ^ BaseType.GetHashCode(); - hash = ((hash << 5) + hash) ^ (AttributeType ?? typeof (TypeListKey)).GetHashCode(); + hash = ((hash << 5) + hash) ^ (AttributeType ?? typeof(TypeListKey)).GetHashCode(); return hash; } } @@ -892,7 +917,7 @@ namespace Umbraco.Core { // look for IParameterEditor (fast, IDiscoverable) then filter - var propertyEditor = typeof (PropertyEditor); + var propertyEditor = typeof(PropertyEditor); return mgr.ResolveTypes() .Where(x => propertyEditor.IsAssignableFrom(x) && x != propertyEditor); @@ -907,8 +932,8 @@ namespace Umbraco.Core /// public static IEnumerable ResolveParameterEditors(this PluginManager mgr) { - var propertyEditor = typeof (PropertyEditor); - var parameterEditor = typeof (ParameterEditor); + var propertyEditor = typeof(PropertyEditor); + var parameterEditor = typeof(ParameterEditor); return mgr.ResolveTypes() .Where(x => x != propertyEditor && x != parameterEditor); @@ -990,4 +1015,4 @@ namespace Umbraco.Core return mgr.ResolveTypesWithAttribute(); } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index 12cb465b50..6f1fc03281 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using umbraco.interfaces; +using Umbraco.Core.Configuration; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Sync @@ -39,6 +40,7 @@ namespace Umbraco.Core.Sync private bool _syncing; private bool _released; private readonly ProfilingLogger _profilingLogger; + private readonly Lazy _distCacheFilePath = new Lazy(GetDistCacheFilePath); protected DatabaseServerMessengerOptions Options { get; private set; } protected ApplicationContext ApplicationContext { get { return _appContext; } } @@ -460,10 +462,9 @@ namespace Umbraco.Core.Sync /// private void ReadLastSynced() { - var path = SyncFilePath; - if (File.Exists(path) == false) return; + if (File.Exists(_distCacheFilePath.Value) == false) return; - var content = File.ReadAllText(path); + var content = File.ReadAllText(_distCacheFilePath.Value); int last; if (int.TryParse(content, out last)) _lastId = last; @@ -478,7 +479,7 @@ namespace Umbraco.Core.Sync /// private void SaveLastSynced(int id) { - File.WriteAllText(SyncFilePath, id.ToString(CultureInfo.InvariantCulture)); + File.WriteAllText(_distCacheFilePath.Value, id.ToString(CultureInfo.InvariantCulture)); _lastId = id; } @@ -498,20 +499,40 @@ namespace Umbraco.Core.Sync + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique - /// - /// Gets the sync file path for the local server. - /// - /// The sync file path for the local server. - private static string SyncFilePath + private static string GetDistCacheFilePath() { - get - { - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache/" + NetworkHelper.FileSafeMachineName); - if (Directory.Exists(tempFolder) == false) - Directory.CreateDirectory(tempFolder); + var fileName = HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt"; - return Path.Combine(tempFolder, HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt"); + string distCacheFilePath; + switch (GlobalSettings.LocalTempStorageLocation) + { + case LocalTempStorage.AspNetTemp: + distCacheFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData", fileName); + break; + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + distCacheFilePath = Path.Combine(cachePath, fileName); + break; + case LocalTempStorage.Default: + default: + var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache"); + distCacheFilePath = Path.Combine(tempFolder, fileName); + break; } + + //ensure the folder exists + var folder = Path.GetDirectoryName(distCacheFilePath); + if (folder == null) + throw new InvalidOperationException("The folder could not be determined for the file " + distCacheFilePath); + if (Directory.Exists(folder) == false) + Directory.CreateDirectory(folder); + + return distCacheFilePath; } #endregion diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 4244188697..aa9fc35524 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -20,7 +20,7 @@ using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.Models { [TestFixture] - public class ContentTests : BaseUmbracoConfigurationTest + public class ContentTests : BaseUmbracoApplicationTest { [SetUp] public void Init() diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index 87af8f3234..6e2517a4d7 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -118,27 +118,14 @@ namespace Umbraco.Tests.TestHelpers } } - /// - /// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan - /// all of the assemblies. Inheritors can override this if plugin manager resetting is required, generally needs - /// to be set to true if the SetupPluginManager has been overridden. - /// - protected virtual bool PluginManagerResetRequired - { - get { return false; } - } - /// /// Inheritors can resset the plugin manager if they choose to on teardown /// protected virtual void ResetPluginManager() - { - if (PluginManagerResetRequired) - { - PluginManager.Current = null; - } - } - + { + PluginManager.Current = null; + } + protected virtual CacheHelper CreateCacheHelper() { return CacheHelper.CreateDisabledCacheHelper(); @@ -166,10 +153,10 @@ namespace Umbraco.Tests.TestHelpers var dbFactory = new DefaultDatabaseFactory(Constants.System.UmbracoConnectionName, Logger); var scopeProvider = new ScopeProvider(dbFactory); var evtMsgs = new TransientMessagesFactory(); - var applicationContext = new ApplicationContext( - //assign the db context - new DatabaseContext(scopeProvider, Logger, sqlSyntax, Constants.DatabaseProviders.SqlCe), - //assign the service context + var applicationContext = new ApplicationContext( + //assign the db context + new DatabaseContext(scopeProvider, Logger, sqlSyntax, Constants.DatabaseProviders.SqlCe), + //assign the service context new ServiceContext(repoFactory, new PetaPocoUnitOfWorkProvider(scopeProvider), CacheHelper, Logger, evtMsgs), CacheHelper, ProfilingLogger) @@ -185,26 +172,23 @@ namespace Umbraco.Tests.TestHelpers /// protected virtual void SetupPluginManager() { - if (PluginManager.Current == null || PluginManagerResetRequired) + PluginManager.Current = new PluginManager( + new ActivatorServiceProvider(), + CacheHelper.RuntimeCache, ProfilingLogger, false) { - PluginManager.Current = new PluginManager( - new ActivatorServiceProvider(), - CacheHelper.RuntimeCache, ProfilingLogger, false) + AssembliesToScan = new[] { - AssembliesToScan = new[] - { - Assembly.Load("Umbraco.Core"), - Assembly.Load("umbraco"), - Assembly.Load("Umbraco.Tests"), - Assembly.Load("businesslogic"), - Assembly.Load("cms"), - Assembly.Load("controls"), - Assembly.Load("umbraco.editorControls"), - Assembly.Load("umbraco.MacroEngines"), - Assembly.Load("umbraco.providers"), - } - }; - } + Assembly.Load("Umbraco.Core"), + Assembly.Load("umbraco"), + Assembly.Load("Umbraco.Tests"), + Assembly.Load("businesslogic"), + Assembly.Load("cms"), + Assembly.Load("controls"), + Assembly.Load("umbraco.editorControls"), + Assembly.Load("umbraco.MacroEngines"), + Assembly.Load("umbraco.providers"), + } + }; } ///