diff --git a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs index 1d45920e3..8bbbc3806 100644 --- a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs +++ b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Autofac; using NUnit.Framework; +using Orchard.Caching; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Loaders; @@ -57,6 +58,10 @@ namespace Orchard.Tests.Environment.Extensions { return new ExtensionEntry { Descriptor = entry.Descriptor, ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) } }; } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + throw new NotImplementedException(); + } + #endregion } diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index a94d69477..5880281c0 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -1,10 +1,8 @@ -using System; using System.Linq; using System.Threading; using System.Web.Mvc; -using Autofac; using System.Collections.Generic; -using Autofac.Features.OwnedInstances; +using Orchard.Caching; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Environment.ShellBuilders; @@ -17,13 +15,15 @@ using Orchard.Mvc.ViewEngines; using Orchard.Utility.Extensions; namespace Orchard.Environment { - public class DefaultOrchardHost : IOrchardHost, IShellSettingsManagerEventHandler, IShellDescriptorManagerEventHandler, IExtensionManagerEvents { + public class DefaultOrchardHost : IOrchardHost, IShellSettingsManagerEventHandler, IShellDescriptorManagerEventHandler { private readonly ControllerBuilder _controllerBuilder; private readonly IShellSettingsManager _shellSettingsManager; private readonly IShellContextFactory _shellContextFactory; private readonly IRunningShellTable _runningShellTable; private readonly IProcessingEngine _processingEngine; + private readonly IExtensionManager _extensionManager; + private readonly ICacheManager _cacheManager; private IEnumerable _current; @@ -32,12 +32,15 @@ namespace Orchard.Environment { IShellContextFactory shellContextFactory, IRunningShellTable runningShellTable, IProcessingEngine processingEngine, + IExtensionManager extensionManager, + ICacheManager cacheManager, ControllerBuilder controllerBuilder) { - //_containerProvider = containerProvider; _shellSettingsManager = shellSettingsManager; _shellContextFactory = shellContextFactory; _runningShellTable = runningShellTable; _processingEngine = processingEngine; + _extensionManager = extensionManager; + _cacheManager = cacheManager; _controllerBuilder = controllerBuilder; Logger = NullLogger.Instance; } @@ -117,6 +120,12 @@ namespace Orchard.Environment { } protected virtual void BeginRequest() { + _cacheManager.Get("OrchardHost_Extensions", + ctx => { + _extensionManager.Monitor(ctx.Monitor); + _current = null; + return ""; + }); BuildCurrent(); } @@ -147,9 +156,5 @@ namespace Orchard.Environment { void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) { _current = null; } - - void IExtensionManagerEvents.ModuleChanged(string moduleName) { - _current = null; - } } } diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index 1bd388332..f7e15737f 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Web; using ICSharpCode.SharpZipLib.Zip; +using Orchard.Caching; using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Helpers; using Orchard.Environment.Extensions.Loaders; @@ -32,6 +33,15 @@ namespace Orchard.Environment.Extensions { return _folders.SelectMany(folder => folder.AvailableExtensions()); } + private IEnumerable LoadedModules() { + foreach (var descriptor in AvailableExtensions()) { + // Extensions that are Themes don't have buildable components. + if (String.Equals(descriptor.ExtensionType, "Module", StringComparison.OrdinalIgnoreCase)) { + yield return BuildEntry(descriptor); + } + } + } + public IEnumerable LoadFeatures(IEnumerable featureDescriptors) { return featureDescriptors .Select(featureDescriptor => LoadFeature(featureDescriptor)) @@ -41,9 +51,12 @@ namespace Orchard.Environment.Extensions { private Feature LoadFeature(FeatureDescriptor featureDescriptor) { var featureName = featureDescriptor.Name; string extensionName = GetExtensionForFeature(featureName); - if (extensionName == null) throw new ArgumentException(T("Feature {0} was not found in any of the installed extensions", featureName).ToString()); - var extension = BuildActiveExtensions().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault(); - if (extension == null) throw new InvalidOperationException(T("Extension ") + extensionName + T(" is not active")); + if (extensionName == null) + throw new ArgumentException(T("Feature {0} was not found in any of the installed extensions", featureName).ToString()); + + var extension = LoadedModules().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault(); + if (extension == null) + throw new InvalidOperationException(T("Extension {0} is not active", extensionName).ToString()); var extensionTypes = extension.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract); var featureTypes = new List(); @@ -141,11 +154,12 @@ namespace Orchard.Environment.Extensions { Directory.Delete(targetFolder, true); } - private IEnumerable BuildActiveExtensions() { + public void Monitor(Action monitor) { foreach (var descriptor in AvailableExtensions()) { - // Extensions that are Themes don't have buildable components. - if (String.Equals(descriptor.ExtensionType, "Module", StringComparison.OrdinalIgnoreCase)) { - yield return BuildEntry(descriptor); + if (string.Equals(descriptor.ExtensionType, "Module", StringComparison.OrdinalIgnoreCase)) { + foreach (var loader in _loaders) { + loader.Monitor(descriptor, monitor); + } } } } diff --git a/src/Orchard/Environment/Extensions/IExtensionManager.cs b/src/Orchard/Environment/Extensions/IExtensionManager.cs index be0950a66..27cda4808 100644 --- a/src/Orchard/Environment/Extensions/IExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/IExtensionManager.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Web; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; namespace Orchard.Environment.Extensions { @@ -8,5 +10,6 @@ namespace Orchard.Environment.Extensions { IEnumerable LoadFeatures(IEnumerable featureDescriptors); void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle); void UninstallExtension(string extensionType, string extensionName); + void Monitor(Action monitor); } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/IExtensionManagerEvents.cs b/src/Orchard/Environment/Extensions/IExtensionManagerEvents.cs deleted file mode 100644 index c7be80e9f..000000000 --- a/src/Orchard/Environment/Extensions/IExtensionManagerEvents.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Orchard.Events; - -namespace Orchard.Environment.Extensions { - public interface IExtensionManagerEvents : IEventHandler { - void ModuleChanged(string moduleName); - } -} \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs index e1dbd06b4..d1d227a0c 100644 --- a/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Reflection; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; @@ -17,6 +18,11 @@ namespace Orchard.Environment.Extensions.Loaders { public int Order { get { return 50; } } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + // We don't need to monitor anything since we are loaded + // from the application assembly itself. + } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (descriptor.Location == "~/Areas") { return new ExtensionProbeEntry { diff --git a/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs index ab35c9e9a..e69c1f0e9 100644 --- a/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Reflection; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; @@ -20,6 +21,11 @@ namespace Orchard.Environment.Extensions.Loaders { public int Order { get { return 10; } } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + // We don't need to monitor anything since we are loaded + // from the core assembly. + } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (descriptor.Location == "~/Core") { return new ExtensionProbeEntry { diff --git a/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs index 0b5a5580c..89b0aab4e 100644 --- a/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; @@ -9,23 +10,33 @@ namespace Orchard.Environment.Extensions.Loaders { private readonly IHostEnvironment _hostEnvironment; private readonly IBuildManager _buildManager; private readonly IVirtualPathProvider _virtualPathProvider; + private readonly IVirtualPathMonitor _virtualPathMonitor; private readonly IDependenciesFolder _dependenciesFolder; - public DynamicExtensionLoader(IHostEnvironment hostEnvironment, IBuildManager buildManager, IVirtualPathProvider virtualPathProvider, IDependenciesFolder dependenciesFolder) { + public DynamicExtensionLoader(IHostEnvironment hostEnvironment, + IBuildManager buildManager, + IVirtualPathProvider virtualPathProvider, + IVirtualPathMonitor virtualPathMonitor, + IDependenciesFolder dependenciesFolder) { _hostEnvironment = hostEnvironment; _buildManager = buildManager; _virtualPathProvider = virtualPathProvider; + _virtualPathMonitor = virtualPathMonitor; _dependenciesFolder = dependenciesFolder; } public int Order { get { return 100; } } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + string projectPath = GetProjectPath(descriptor); + if (projectPath != null) + monitor(_virtualPathMonitor.WhenPathChanges(projectPath)); + } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { - string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, - descriptor.Name + ".csproj"); - if (!_virtualPathProvider.FileExists(projectPath)) { + string projectPath = GetProjectPath(descriptor); + if (projectPath == null) return null; - } return new ExtensionProbeEntry { Descriptor = descriptor, @@ -35,6 +46,18 @@ namespace Orchard.Environment.Extensions.Loaders { }; } + private string GetProjectPath(ExtensionDescriptor descriptor) { + string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, + descriptor.Name + ".csproj"); + + if (!_virtualPathProvider.FileExists(projectPath)) { + return null; + } + + return projectPath; + } + + public ExtensionEntry Load(ExtensionProbeEntry entry) { if (entry.Loader == this) { var assembly = _buildManager.GetCompiledAssembly(entry.VirtualPath); diff --git a/src/Orchard/Environment/Extensions/Loaders/IExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/IExtensionLoader.cs index 15be1f554..ae06342a4 100644 --- a/src/Orchard/Environment/Extensions/Loaders/IExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/IExtensionLoader.cs @@ -1,4 +1,5 @@ using System; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; namespace Orchard.Environment.Extensions.Loaders { @@ -6,6 +7,7 @@ namespace Orchard.Environment.Extensions.Loaders { int Order { get; } ExtensionProbeEntry Probe(ExtensionDescriptor descriptor); ExtensionEntry Load(ExtensionProbeEntry descriptor); + void Monitor(ExtensionDescriptor descriptor, Action monitor); } public class ExtensionProbeEntry { diff --git a/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs index 7d51dabc2..2f7ca0655 100644 --- a/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs @@ -1,4 +1,6 @@ -using System.IO; +using System; +using System.IO; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; @@ -11,25 +13,41 @@ namespace Orchard.Environment.Extensions.Loaders { public class PrecompiledExtensionLoader : IExtensionLoader { private readonly IDependenciesFolder _dependenciesFolder; private readonly IVirtualPathProvider _virtualPathProvider; + private readonly IVirtualPathMonitor _virtualPathMonitor; - public PrecompiledExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider) { + public PrecompiledExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider, IVirtualPathMonitor virtualPathMonitor) { _dependenciesFolder = dependenciesFolder; _virtualPathProvider = virtualPathProvider; + _virtualPathMonitor = virtualPathMonitor; } public int Order { get { return 30; } } - public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { - var extensionPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, "bin", + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + string assemblyPath = GetAssemblyPath(descriptor); + if (assemblyPath != null) + monitor(_virtualPathMonitor.WhenPathChanges(assemblyPath)); + } + + public string GetAssemblyPath(ExtensionDescriptor descriptor) { + var assemblyPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, "bin", descriptor.Name + ".dll"); - if (!_virtualPathProvider.FileExists(extensionPath)) + if (!_virtualPathProvider.FileExists(assemblyPath)) + return null; + + return assemblyPath; + } + + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { + var assemblyPath = GetAssemblyPath(descriptor); + if (assemblyPath == null) return null; return new ExtensionProbeEntry { Descriptor = descriptor, - LastModificationTimeUtc = File.GetLastWriteTimeUtc(_virtualPathProvider.MapPath(extensionPath)), + LastModificationTimeUtc = File.GetLastWriteTimeUtc(_virtualPathProvider.MapPath(assemblyPath)), Loader = this, - VirtualPath = extensionPath + VirtualPath = assemblyPath }; } diff --git a/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs index a1dde340a..829055f44 100644 --- a/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs @@ -1,4 +1,6 @@ -using System.IO; +using System; +using System.IO; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; @@ -17,6 +19,12 @@ namespace Orchard.Environment.Extensions.Loaders { public int Order { get { return 40; } } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + // We don't monitor assemblies loaded from this probing directory, + // because they are just a copy of the assemblies from the module + // bin directory. + } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (!_dependenciesFolder.HasPrecompiledAssembly(descriptor.Name)) return null; diff --git a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs index 810c935f0..86d4b8e34 100644 --- a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs @@ -1,8 +1,10 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using System.Reflection; using System.Web.Compilation; using System.Web.Hosting; +using Orchard.Caching; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.Dependencies; @@ -19,6 +21,11 @@ namespace Orchard.Environment.Extensions.Loaders { public int Order { get { return 20; } } + public void Monitor(ExtensionDescriptor descriptor, Action monitor) { + // We don't monitor assemblies loaded from the "~/bin" directory, + // because they are monitored by the ASP.NET runtime. + } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (HostingEnvironment.IsHosted == false) return null; diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index bead55b05..6f77582a6 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -360,7 +360,6 @@ -