mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Couple of fixed with dynamic extension loader
Perf: Use the cache manager to keep the list of dependency descriptors in
memory, with invalidation when "dependencies.xml" changes on disk
When loading an assembly from the list of references assemblies, notify
the dependencies folder component, so it removes the entry.
--HG--
branch : dev
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
/// <summary>
|
||||
/// Load an extension by looking through the BuildManager referenced assemblies
|
||||
/// </summary>
|
||||
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,
|
||||
|
||||
@@ -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<DependencyDescriptor> 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<DependencyDescriptor> ReadDependencies() {
|
||||
if (!_virtualPathProvider.FileExists(PersistencePath))
|
||||
private IEnumerable<DependencyDescriptor> ReadDependencies(string persistancePath) {
|
||||
Func<string, XName> ns = (name => XName.Get(name));
|
||||
|
||||
if (!_virtualPathProvider.FileExists(persistancePath))
|
||||
return Enumerable.Empty<DependencyDescriptor>();
|
||||
|
||||
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<DependencyDescriptor> dependencies) {
|
||||
private void WriteDependencies(string persistancePath, IEnumerable<DependencyDescriptor> dependencies) {
|
||||
Func<string, XName> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<Token> 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) {
|
||||
|
||||
Reference in New Issue
Block a user