diff --git a/src/Orchard.Tests/Stubs/StubWebSiteFolder.cs b/src/Orchard.Tests/Stubs/StubWebSiteFolder.cs index 82e0446ee..211824fea 100644 --- a/src/Orchard.Tests/Stubs/StubWebSiteFolder.cs +++ b/src/Orchard.Tests/Stubs/StubWebSiteFolder.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -23,5 +24,9 @@ namespace Orchard.Tests.Stubs { public IVolatileToken WhenPathChanges(string path) { return new WebSiteFolder.Token(path); } + + public void WhenPathChanges(string path, Action action) { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs index 39b8a19f0..4ce622ef7 100644 --- a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs @@ -3,14 +3,20 @@ using System.Reflection; using System.Web.Compilation; using System.Web.Hosting; using Orchard.Environment.Extensions.Models; +using Orchard.FileSystems.Dependencies; namespace Orchard.Environment.Extensions.Loaders { /// /// Load an extension by looking through the BuildManager referenced assemblies /// public class ReferencedExtensionLoader : IExtensionLoader { + private readonly IDependenciesFolder _dependenciesFolder; public int Order { get { return 20; } } + public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder) { + _dependenciesFolder = dependenciesFolder; + } + public ExtensionEntry Load(ExtensionDescriptor descriptor) { if (HostingEnvironment.IsHosted == false) return null; @@ -22,6 +28,8 @@ namespace Orchard.Environment.Extensions.Loaders { if (assembly == null) return null; + _dependenciesFolder.StoreReferencedAssembly(descriptor.Name); + return new ExtensionEntry { Descriptor = descriptor, Assembly = assembly, diff --git a/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs b/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs index 321f74e16..d3d87d60a 100644 --- a/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs +++ b/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Web.Caching; -using System.Web.Hosting; using System.Xml.Linq; using Orchard.Caching; using Orchard.Environment; using Orchard.Environment.Extensions; -using Orchard.Environment.Topology; +using Orchard.FileSystems.WebSite; namespace Orchard.FileSystems.Dependencies { public class DependencyDescriptor { @@ -20,21 +18,27 @@ namespace Orchard.FileSystems.Dependencies { } public interface IDependenciesFolder : IVolatileProvider { - void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly); + void StoreReferencedAssembly(string moduleName); void StorePrecompiledAssembly(string moduleName, string virtualPath); + void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly); DependencyDescriptor GetDescriptor(string moduleName); Assembly LoadAssembly(string assemblyName); } public class DefaultDependenciesFolder : IDependenciesFolder { - private readonly string _prefix = Guid.NewGuid().ToString("n"); - private const string _basePath = "~/App_Data/Dependencies"; + private readonly string _basePath = "~/App_Data/Dependencies"; + private readonly ICacheManager _cacheManager; + private readonly IWebSiteFolder _webSiteFolder; private readonly IVirtualPathProvider _virtualPathProvider; private readonly IExtensionManagerEvents _events; + private readonly InvalidationToken _token; - public DefaultDependenciesFolder(IVirtualPathProvider virtualPathProvider, IExtensionManagerEvents events) { + public DefaultDependenciesFolder(ICacheManager cacheManager, IWebSiteFolder webSiteFolder, IVirtualPathProvider virtualPathProvider, IExtensionManagerEvents events) { + _cacheManager = cacheManager; + _webSiteFolder = webSiteFolder; _virtualPathProvider = virtualPathProvider; _events = events; + _token = new InvalidationToken(); } private string BasePath { @@ -49,9 +53,33 @@ namespace Orchard.FileSystems.Dependencies { } } - public void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly) { - _virtualPathProvider.CreateDirectory(BasePath); + private IList Descriptors { + get { + return _cacheManager.Get(PersistencePath, + ctx => { + ctx.Monitor(_webSiteFolder.WhenPathChanges(ctx.Key)); + ctx.Monitor(_token); + _virtualPathProvider.CreateDirectory(BasePath); + return ReadDependencies(ctx.Key); + }); + } + } + + public class InvalidationToken : IVolatileToken { + public bool IsCurrent { get; set; } + } + + public void StoreReferencedAssembly(string moduleName) { + if (Descriptors.Any(d => d.ModuleName == moduleName)) { + // Remove the moduleName from the list of assemblies in the dependency folder + var newDescriptors = Descriptors.Where(d => d.ModuleName != moduleName); + + WriteDependencies(PersistencePath, newDescriptors); + } + } + + public void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly) { var descriptor = new DependencyDescriptor { ModuleName = moduleName, IsFromBuildProvider = true, @@ -61,21 +89,7 @@ namespace Orchard.FileSystems.Dependencies { StoreDepencyInformation(descriptor); -#if true - var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency( - virtualPath, - new[] { virtualPath }, - DateTime.UtcNow); - - HostingEnvironment.Cache.Add( - _prefix + virtualPath, - moduleName, - cacheDependency, - Cache.NoAbsoluteExpiration, - Cache.NoSlidingExpiration, - CacheItemPriority.NotRemovable, - (key, value, reason) => _events.ModuleChanged((string) value)); -#endif + _webSiteFolder.WhenPathChanges(virtualPath, () => _events.ModuleChanged(moduleName)); } public void StorePrecompiledAssembly(string moduleName, string virtualPath) { @@ -98,11 +112,11 @@ namespace Orchard.FileSystems.Dependencies { } public DependencyDescriptor GetDescriptor(string moduleName) { - return ReadDependencies().SingleOrDefault(d => d.ModuleName == moduleName); + return Descriptors.SingleOrDefault(d => d.ModuleName == moduleName); } private bool IsNewerAssembly(string moduleName, string assemblyFileName) { - var dependency = ReadDependencies().SingleOrDefault(d => d.ModuleName == moduleName); + var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == moduleName); if (dependency == null) { return true; } @@ -116,7 +130,7 @@ namespace Orchard.FileSystems.Dependencies { } private void StoreDepencyInformation(DependencyDescriptor descriptor) { - var dependencies = ReadDependencies().ToList(); + var dependencies = Descriptors.ToList(); int index = dependencies.FindIndex(d => d.ModuleName == descriptor.ModuleName); if (index < 0) { dependencies.Add(descriptor); @@ -125,13 +139,13 @@ namespace Orchard.FileSystems.Dependencies { dependencies[index] = descriptor; } - WriteDependencies(dependencies); + WriteDependencies(PersistencePath, dependencies); } public Assembly LoadAssembly(string assemblyName) { _virtualPathProvider.CreateDirectory(BasePath); - var dependency = ReadDependencies().SingleOrDefault(d => d.ModuleName == assemblyName); + var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == assemblyName); if (dependency == null) return null; @@ -141,11 +155,13 @@ namespace Orchard.FileSystems.Dependencies { return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName)); } - private IEnumerable ReadDependencies() { - if (!_virtualPathProvider.FileExists(PersistencePath)) + private IEnumerable ReadDependencies(string persistancePath) { + Func ns = (name => XName.Get(name)); + + if (!_virtualPathProvider.FileExists(persistancePath)) return Enumerable.Empty(); - using (var stream = _virtualPathProvider.OpenFile(PersistencePath)) { + using (var stream = _virtualPathProvider.OpenFile(persistancePath)) { XDocument document = XDocument.Load(stream); return document .Elements(ns("Dependencies")) @@ -160,7 +176,9 @@ namespace Orchard.FileSystems.Dependencies { } } - private void WriteDependencies(IEnumerable dependencies) { + private void WriteDependencies(string persistancePath, IEnumerable dependencies) { + Func ns = (name => XName.Get(name)); + var document = new XDocument(); document.Add(new XElement(ns("Dependencies"))); var elements = dependencies.Select(d => new XElement("Dependency", @@ -170,13 +188,12 @@ namespace Orchard.FileSystems.Dependencies { new XElement(ns("FileName"), d.FileName))); document.Root.Add(elements); - using (var stream = _virtualPathProvider.CreateText(PersistencePath)) { + using (var stream = _virtualPathProvider.CreateText(persistancePath)) { document.Save(stream, SaveOptions.None); } - } - private static XName ns(string name) { - return XName.Get(name/*, "http://schemas.microsoft.com/developer/msbuild/2003"*/); + // Ensure cache is invalidated right away, not waiting for file change notification to happen + _token.IsCurrent = false; } } } diff --git a/src/Orchard/FileSystems/WebSite/IWebSiteFolder.cs b/src/Orchard/FileSystems/WebSite/IWebSiteFolder.cs index a7dc73925..8836d2009 100644 --- a/src/Orchard/FileSystems/WebSite/IWebSiteFolder.cs +++ b/src/Orchard/FileSystems/WebSite/IWebSiteFolder.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Orchard.Caching; namespace Orchard.FileSystems.WebSite { @@ -7,5 +8,6 @@ namespace Orchard.FileSystems.WebSite { string ReadFile(string path); IVolatileToken WhenPathChanges(string path); + void WhenPathChanges(string path, Action action); } } \ No newline at end of file diff --git a/src/Orchard/FileSystems/WebSite/WebSiteFolder.cs b/src/Orchard/FileSystems/WebSite/WebSiteFolder.cs index d82eec4f9..d5b2ddd4b 100644 --- a/src/Orchard/FileSystems/WebSite/WebSiteFolder.cs +++ b/src/Orchard/FileSystems/WebSite/WebSiteFolder.cs @@ -49,6 +49,10 @@ namespace Orchard.FileSystems.WebSite { return token; } + public void WhenPathChanges(string virtualPath, Action action) { + BindSignal(virtualPath, (key, value, reason) => action()); + } + private Token BindToken(string virtualPath) { lock (_tokens) { Weak weak; @@ -80,6 +84,11 @@ namespace Orchard.FileSystems.WebSite { } private void BindSignal(string virtualPath) { + BindSignal(virtualPath, _thunk.Signal); + + } + + private void BindSignal(string virtualPath, CacheItemRemovedCallback callback) { var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency( virtualPath, new[] { virtualPath }, @@ -92,7 +101,7 @@ namespace Orchard.FileSystems.WebSite { Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, - _thunk.Signal); + callback); } public void Signal(string key, object value, CacheItemRemovedReason reason) {