mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-14 10:54:50 +08:00
Refactor IAppDataFolder and default implementation
Refactor IAppDataFolder so that it can be used for implementing DefaultDependenciesFolder. --HG-- branch : dev rename : src/Orchard/Environment/Extensions/Loaders/WebFormsExtensionsVirtualFile.cs => src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualFile.cs rename : src/Orchard/Environment/Extensions/Loaders/WebFormsExtensionsVirtualPathProvider.cs => src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualPathProvider.cs rename : src/Orchard/Environment/IVirtualPathProvider.cs => src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathProvider.cs rename : src/Orchard/Environment/ICustomVirtualPathProvider.cs => src/Orchard/FileSystems/VirtualPath/ICustomVirtualPathProvider.cs
This commit is contained in:
@@ -3,10 +3,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Indexing;
|
||||
using Orchard.Core.Indexing.Lucene;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Indexing {
|
||||
public class DefaultIndexProviderTests {
|
||||
@@ -28,7 +31,7 @@ namespace Orchard.Tests.Indexing {
|
||||
}
|
||||
Directory.CreateDirectory(_basePath);
|
||||
|
||||
_appDataFolder = new AppDataFolder();
|
||||
_appDataFolder = new AppDataFolder(new DefaultVirtualPathMonitor(new Clock()));
|
||||
_appDataFolder.SetBasePath(_basePath);
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
|
@@ -3,10 +3,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Indexing;
|
||||
using Orchard.Core.Indexing.Lucene;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Indexing {
|
||||
public class DefaultSearchBuilderTests {
|
||||
@@ -29,7 +32,7 @@ namespace Orchard.Tests.Indexing {
|
||||
Directory.CreateDirectory(_basePath);
|
||||
|
||||
|
||||
_appDataFolder = new AppDataFolder();
|
||||
_appDataFolder = new AppDataFolder(new DefaultVirtualPathMonitor(new Clock()));
|
||||
_appDataFolder.SetBasePath(_basePath);
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
|
@@ -1,7 +1,10 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Environment.Configuration {
|
||||
[TestFixture]
|
||||
@@ -18,7 +21,7 @@ namespace Orchard.Tests.Environment.Configuration {
|
||||
File.WriteAllText(Path.Combine(_tempFolder, "alpha\\gamma.txt"), "gamma-content");
|
||||
Directory.CreateDirectory(Path.Combine(_tempFolder, "alpha\\omega"));
|
||||
|
||||
_appDataFolder = new AppDataFolder();
|
||||
_appDataFolder = new AppDataFolder(new DefaultVirtualPathMonitor(new Clock()));
|
||||
_appDataFolder.SetBasePath(_tempFolder);
|
||||
}
|
||||
|
||||
@@ -31,8 +34,8 @@ namespace Orchard.Tests.Environment.Configuration {
|
||||
public void ListFilesShouldContainSubPathAndFileName() {
|
||||
var files = _appDataFolder.ListFiles("alpha");
|
||||
Assert.That(files.Count(), Is.EqualTo(2));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha\\beta.txt"));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha\\gamma.txt"));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha/beta.txt"));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha/gamma.txt"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -51,7 +54,7 @@ namespace Orchard.Tests.Environment.Configuration {
|
||||
public void ListSubdirectoriesShouldContainFullSubpath() {
|
||||
var files = _appDataFolder.ListDirectories("alpha");
|
||||
Assert.That(files.Count(), Is.EqualTo(1));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha\\omega"));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha/omega"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@@ -2,8 +2,11 @@
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Environment.Configuration {
|
||||
[TestFixture]
|
||||
@@ -13,7 +16,7 @@ namespace Orchard.Tests.Environment.Configuration {
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_appData = new AppDataFolder();
|
||||
_appData = new AppDataFolder(new DefaultVirtualPathMonitor(new Clock()));
|
||||
_tempFolder = Path.GetTempFileName();
|
||||
File.Delete(_tempFolder);
|
||||
_appData.SetBasePath(_tempFolder);
|
||||
|
@@ -3,9 +3,12 @@ using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Topology;
|
||||
using Orchard.Environment.Topology.Models;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Environment.Topology {
|
||||
[TestFixture]
|
||||
@@ -19,7 +22,7 @@ namespace Orchard.Tests.Environment.Topology {
|
||||
_tempFolder = Path.GetTempFileName();
|
||||
File.Delete(_tempFolder);
|
||||
Directory.CreateDirectory(_tempFolder);
|
||||
_appDataFolder = new AppDataFolder();
|
||||
_appDataFolder = new AppDataFolder(new DefaultVirtualPathMonitor(new Clock()));
|
||||
_appDataFolder.SetBasePath(_tempFolder);
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();
|
||||
|
@@ -22,11 +22,15 @@ namespace Orchard.Tests.Stubs {
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string path) {
|
||||
return new WebSiteFolder.Token(path);
|
||||
return new Token {IsCurrent = true};
|
||||
}
|
||||
|
||||
public void WhenPathChanges(string path, Action action) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public class Token : IVolatileToken {
|
||||
public bool IsCurrent { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Compilation;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
public class CSharpExtensionBuildProvider : BuildProvider {
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <summary>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System.CodeDom;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <summary>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
public class DynamicExtensionLoader : IExtensionLoader {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
|
@@ -17,6 +17,7 @@ using Orchard.Environment.Topology;
|
||||
using Orchard.Events;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Services;
|
||||
@@ -40,6 +41,7 @@ namespace Orchard.Environment {
|
||||
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
|
||||
RegisterVolatileProvider<Clock, IClock>(builder);
|
||||
RegisterVolatileProvider<DefaultDependenciesFolder, IDependenciesFolder>(builder);
|
||||
RegisterVolatileProvider<DefaultVirtualPathMonitor, IVirtualPathMonitor>(builder);
|
||||
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);
|
||||
|
||||
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().As<IEventHandler>().SingleInstance();
|
||||
@@ -123,11 +125,12 @@ namespace Orchard.Environment {
|
||||
//
|
||||
// Register Virtual Path Providers
|
||||
//
|
||||
foreach (var vpp in container.Resolve<IEnumerable<ICustomVirtualPathProvider>>()) {
|
||||
HostingEnvironment.RegisterVirtualPathProvider(vpp.Instance);
|
||||
if (HostingEnvironment.IsHosted) {
|
||||
foreach (var vpp in container.Resolve<IEnumerable<ICustomVirtualPathProvider>>()) {
|
||||
HostingEnvironment.RegisterVirtualPathProvider(vpp.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return container.Resolve<IOrchardHost>();
|
||||
}
|
||||
}
|
||||
|
@@ -1,39 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.FileSystems.AppData {
|
||||
public class AppDataFolder : IAppDataFolder {
|
||||
private readonly IVirtualPathMonitor _virtualPathMonitor;
|
||||
protected string _basePath;
|
||||
|
||||
public AppDataFolder() {
|
||||
public AppDataFolder(IVirtualPathMonitor virtualPathMonitor) {
|
||||
_virtualPathMonitor = virtualPathMonitor;
|
||||
_basePath = HostingEnvironment.MapPath("~/App_Data");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combine a set of virtual paths into a physical path based at "_basePath"
|
||||
/// </summary>
|
||||
private string CombineToPhysicalPath(params string[] paths) {
|
||||
return Path.Combine(_basePath, Path.Combine(paths))
|
||||
.Replace('/', Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string path) {
|
||||
var replace = Path.Combine("~/App_Data", path).Replace(Path.DirectorySeparatorChar, '/');
|
||||
return _virtualPathMonitor.WhenPathChanges(replace);
|
||||
}
|
||||
|
||||
public void CreateFile(string path, string content) {
|
||||
var filePath = Path.Combine(_basePath, path);
|
||||
using(var stream = CreateFile(path)) {
|
||||
using(var tw = new StreamWriter(stream)) {
|
||||
tw.Write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Stream CreateFile(string path) {
|
||||
var filePath = CombineToPhysicalPath(path);
|
||||
var folderPath = Path.GetDirectoryName(filePath);
|
||||
if (!Directory.Exists(folderPath))
|
||||
Directory.CreateDirectory(folderPath);
|
||||
File.WriteAllText(filePath, content);
|
||||
return File.Create(filePath);
|
||||
}
|
||||
|
||||
public string ReadFile(string path) {
|
||||
return File.ReadAllText(Path.Combine(_basePath, path));
|
||||
return File.ReadAllText(CombineToPhysicalPath(path));
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path) {
|
||||
return File.OpenRead(CombineToPhysicalPath(path));
|
||||
}
|
||||
|
||||
public void DeleteFile(string path) {
|
||||
File.Delete(Path.Combine(_basePath, path));
|
||||
File.Delete(CombineToPhysicalPath(path));
|
||||
}
|
||||
|
||||
public bool FileExists(string path) {
|
||||
var filePath = Path.Combine(_basePath, path);
|
||||
var filePath = CombineToPhysicalPath(path);
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
|
||||
public string Combine(params string[] paths) {
|
||||
return Path.Combine(paths).Replace(Path.DirectorySeparatorChar, '/');
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListFiles(string path) {
|
||||
var directoryPath = Path.Combine(_basePath, path);
|
||||
var directoryPath = CombineToPhysicalPath(path);
|
||||
if (!Directory.Exists(directoryPath))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
@@ -41,12 +76,12 @@ namespace Orchard.FileSystems.AppData {
|
||||
|
||||
return files.Select(file => {
|
||||
var fileName = Path.GetFileName(file);
|
||||
return Path.Combine(path, fileName);
|
||||
return Combine(path, fileName);
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListDirectories(string path) {
|
||||
var directoryPath = Path.Combine(_basePath, path);
|
||||
var directoryPath = CombineToPhysicalPath(path);
|
||||
if (!Directory.Exists(directoryPath))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
@@ -54,12 +89,12 @@ namespace Orchard.FileSystems.AppData {
|
||||
|
||||
return files.Select(file => {
|
||||
var fileName = Path.GetFileName(file);
|
||||
return Path.Combine(path, fileName);
|
||||
return Combine(path, fileName);
|
||||
});
|
||||
}
|
||||
|
||||
public string CreateDirectory(string path) {
|
||||
var directory = Path.Combine(_basePath, path);
|
||||
var directory = CombineToPhysicalPath(path);
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
return directory;
|
||||
@@ -70,8 +105,7 @@ namespace Orchard.FileSystems.AppData {
|
||||
}
|
||||
|
||||
public string MapPath(string path) {
|
||||
return Path.Combine(_basePath, path);
|
||||
return CombineToPhysicalPath(path);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.FileSystems.AppData {
|
||||
@@ -11,13 +13,20 @@ namespace Orchard.FileSystems.AppData {
|
||||
IEnumerable<string> ListFiles(string path);
|
||||
IEnumerable<string> ListDirectories(string path);
|
||||
|
||||
void CreateFile(string path, string content);
|
||||
string ReadFile(string path);
|
||||
void DeleteFile(string path);
|
||||
bool FileExists(string path);
|
||||
string Combine(params string[] paths);
|
||||
|
||||
void CreateFile(string path, string content);
|
||||
Stream CreateFile(string path);
|
||||
|
||||
string ReadFile(string path);
|
||||
Stream OpenFile(string path);
|
||||
|
||||
void DeleteFile(string path);
|
||||
|
||||
string CreateDirectory(string path);
|
||||
|
||||
IVolatileToken WhenPathChanges(string path);
|
||||
|
||||
/// <summary>
|
||||
/// May be called to initialize component when not in a hosting environment
|
||||
|
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public class DefaultDependenciesFolder : IDependenciesFolder {
|
||||
private readonly string _basePath = "Dependencies";
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly IWebSiteFolder _webSiteFolder;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly IExtensionManagerEvents _events;
|
||||
private readonly InvalidationToken _writeThroughToken;
|
||||
|
||||
public DefaultDependenciesFolder(ICacheManager cacheManager, IWebSiteFolder webSiteFolder, IAppDataFolder appDataFolder, IExtensionManagerEvents events) {
|
||||
_cacheManager = cacheManager;
|
||||
_webSiteFolder = webSiteFolder;
|
||||
_appDataFolder = appDataFolder;
|
||||
_events = events;
|
||||
_writeThroughToken = new InvalidationToken();
|
||||
}
|
||||
|
||||
private string BasePath {
|
||||
get {
|
||||
return _basePath;
|
||||
}
|
||||
}
|
||||
|
||||
private string PersistencePath {
|
||||
get {
|
||||
return _appDataFolder.Combine(BasePath, "dependencies.xml");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<DependencyDescriptor> Descriptors {
|
||||
get {
|
||||
return _cacheManager.Get(PersistencePath,
|
||||
ctx => {
|
||||
ctx.Monitor(_appDataFolder.WhenPathChanges(ctx.Key));
|
||||
ctx.Monitor(_writeThroughToken);
|
||||
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
return ReadDependencies(ctx.Key).ToList();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
VirtualPath = virtualPath,
|
||||
FileName = assembly.Location
|
||||
};
|
||||
|
||||
StoreDepencyInformation(descriptor);
|
||||
|
||||
_webSiteFolder.WhenPathChanges(virtualPath, () => _events.ModuleChanged(moduleName));
|
||||
}
|
||||
|
||||
public void StorePrecompiledAssembly(string moduleName, string virtualPath) {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
// Only store assembly if it's more recent that what we have stored already (if anything)
|
||||
var assemblyFileName = _appDataFolder.MapPath(virtualPath);
|
||||
if (IsNewerAssembly(moduleName, assemblyFileName)) {
|
||||
var destinationFileName = Path.GetFileName(assemblyFileName);
|
||||
var destinationPath = _appDataFolder.MapPath(_appDataFolder.Combine(BasePath, destinationFileName));
|
||||
File.Copy(assemblyFileName, destinationPath, true);
|
||||
|
||||
StoreDepencyInformation(new DependencyDescriptor {
|
||||
ModuleName = moduleName,
|
||||
IsFromBuildProvider = false,
|
||||
VirtualPath = virtualPath,
|
||||
FileName = destinationFileName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public DependencyDescriptor GetDescriptor(string moduleName) {
|
||||
return Descriptors.SingleOrDefault(d => d.ModuleName == moduleName);
|
||||
}
|
||||
|
||||
private bool IsNewerAssembly(string moduleName, string assemblyFileName) {
|
||||
var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == moduleName);
|
||||
if (dependency == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var existingFileName = _appDataFolder.MapPath(_appDataFolder.Combine(BasePath, dependency.FileName));
|
||||
if (!File.Exists(existingFileName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (File.GetLastWriteTimeUtc(existingFileName) < File.GetLastWriteTimeUtc(assemblyFileName));
|
||||
}
|
||||
|
||||
private void StoreDepencyInformation(DependencyDescriptor descriptor) {
|
||||
var dependencies = Descriptors.ToList();
|
||||
int index = dependencies.FindIndex(d => d.ModuleName == descriptor.ModuleName);
|
||||
if (index < 0) {
|
||||
dependencies.Add(descriptor);
|
||||
}
|
||||
else {
|
||||
dependencies[index] = descriptor;
|
||||
}
|
||||
|
||||
WriteDependencies(PersistencePath, dependencies);
|
||||
}
|
||||
|
||||
public Assembly LoadAssembly(string assemblyName) {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == assemblyName);
|
||||
if (dependency == null)
|
||||
return null;
|
||||
|
||||
if (!_appDataFolder.FileExists(_appDataFolder.Combine(BasePath, dependency.FileName)))
|
||||
return null;
|
||||
|
||||
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
|
||||
}
|
||||
|
||||
private IEnumerable<DependencyDescriptor> ReadDependencies(string persistancePath) {
|
||||
Func<string, XName> ns = (name => XName.Get(name));
|
||||
Func<XElement, string, string> elem = (e, name) => e.Element(ns(name)).Value;
|
||||
|
||||
if (!_appDataFolder.FileExists(persistancePath))
|
||||
return Enumerable.Empty<DependencyDescriptor>();
|
||||
|
||||
using (var stream = _appDataFolder.OpenFile(persistancePath)) {
|
||||
XDocument document = XDocument.Load(stream);
|
||||
return document
|
||||
.Elements(ns("Dependencies"))
|
||||
.Elements(ns("Dependency"))
|
||||
.Select(e => new DependencyDescriptor {
|
||||
ModuleName = elem(e, "ModuleName"),
|
||||
VirtualPath = elem(e, "VirtualPath"),
|
||||
FileName = elem(e, "FileName"),
|
||||
IsFromBuildProvider = bool.Parse(elem(e, "IsFromBuildProvider"))
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
new XElement(ns("ModuleName"), d.ModuleName),
|
||||
new XElement(ns("VirtualPath"), d.VirtualPath),
|
||||
new XElement(ns("IsFromBuildProvider"), d.IsFromBuildProvider),
|
||||
new XElement(ns("FileName"), d.FileName)));
|
||||
document.Root.Add(elements);
|
||||
|
||||
using (var stream = _appDataFolder.CreateFile(persistancePath)) {
|
||||
document.Save(stream, SaveOptions.None);
|
||||
}
|
||||
|
||||
// Ensure cache is invalidated right away, not waiting for file change notification to happen
|
||||
_writeThroughToken.IsCurrent = false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,13 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public class DependencyDescriptor {
|
||||
@@ -24,176 +17,4 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
DependencyDescriptor GetDescriptor(string moduleName);
|
||||
Assembly LoadAssembly(string assemblyName);
|
||||
}
|
||||
|
||||
public class DefaultDependenciesFolder : IDependenciesFolder {
|
||||
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(ICacheManager cacheManager, IWebSiteFolder webSiteFolder, IVirtualPathProvider virtualPathProvider, IExtensionManagerEvents events) {
|
||||
_cacheManager = cacheManager;
|
||||
_webSiteFolder = webSiteFolder;
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
_events = events;
|
||||
_token = new InvalidationToken();
|
||||
}
|
||||
|
||||
private string BasePath {
|
||||
get {
|
||||
return _basePath;
|
||||
}
|
||||
}
|
||||
|
||||
private string PersistencePath {
|
||||
get {
|
||||
return _virtualPathProvider.Combine(BasePath, "dependencies.xml");
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
VirtualPath = virtualPath,
|
||||
FileName = assembly.Location
|
||||
};
|
||||
|
||||
StoreDepencyInformation(descriptor);
|
||||
|
||||
_webSiteFolder.WhenPathChanges(virtualPath, () => _events.ModuleChanged(moduleName));
|
||||
}
|
||||
|
||||
public void StorePrecompiledAssembly(string moduleName, string virtualPath) {
|
||||
_virtualPathProvider.CreateDirectory(BasePath);
|
||||
|
||||
// Only store assembly if it's more recent that what we have stored already (if anything)
|
||||
var assemblyFileName = _virtualPathProvider.MapPath(virtualPath);
|
||||
if (IsNewerAssembly(moduleName, assemblyFileName)) {
|
||||
var destinationFileName = Path.GetFileName(assemblyFileName);
|
||||
var destinationPath = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, destinationFileName));
|
||||
File.Copy(assemblyFileName, destinationPath, true);
|
||||
|
||||
StoreDepencyInformation(new DependencyDescriptor {
|
||||
ModuleName = moduleName,
|
||||
IsFromBuildProvider = false,
|
||||
VirtualPath = virtualPath,
|
||||
FileName = destinationFileName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public DependencyDescriptor GetDescriptor(string moduleName) {
|
||||
return Descriptors.SingleOrDefault(d => d.ModuleName == moduleName);
|
||||
}
|
||||
|
||||
private bool IsNewerAssembly(string moduleName, string assemblyFileName) {
|
||||
var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == moduleName);
|
||||
if (dependency == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var existingFileName = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, dependency.FileName));
|
||||
if (!File.Exists(existingFileName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (File.GetLastWriteTimeUtc(existingFileName) < File.GetLastWriteTimeUtc(assemblyFileName));
|
||||
}
|
||||
|
||||
private void StoreDepencyInformation(DependencyDescriptor descriptor) {
|
||||
var dependencies = Descriptors.ToList();
|
||||
int index = dependencies.FindIndex(d => d.ModuleName == descriptor.ModuleName);
|
||||
if (index < 0) {
|
||||
dependencies.Add(descriptor);
|
||||
}
|
||||
else {
|
||||
dependencies[index] = descriptor;
|
||||
}
|
||||
|
||||
WriteDependencies(PersistencePath, dependencies);
|
||||
}
|
||||
|
||||
public Assembly LoadAssembly(string assemblyName) {
|
||||
_virtualPathProvider.CreateDirectory(BasePath);
|
||||
|
||||
var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == assemblyName);
|
||||
if (dependency == null)
|
||||
return null;
|
||||
|
||||
if (!_virtualPathProvider.FileExists(_virtualPathProvider.Combine(BasePath, dependency.FileName)))
|
||||
return null;
|
||||
|
||||
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
|
||||
}
|
||||
|
||||
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(persistancePath)) {
|
||||
XDocument document = XDocument.Load(stream);
|
||||
return document
|
||||
.Elements(ns("Dependencies"))
|
||||
.Elements(ns("Dependency"))
|
||||
.Select(e => new DependencyDescriptor {
|
||||
ModuleName = e.Element("ModuleName").Value,
|
||||
VirtualPath = e.Element("VirtualPath").Value,
|
||||
FileName = e.Element("FileName").Value,
|
||||
IsFromBuildProvider = bool.Parse(e.Element("IsFromBuildProvider").Value)
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
new XElement(ns("ModuleName"), d.ModuleName),
|
||||
new XElement(ns("VirtualPath"), d.VirtualPath),
|
||||
new XElement(ns("IsFromBuildProvider"), d.IsFromBuildProvider),
|
||||
new XElement(ns("FileName"), d.FileName)));
|
||||
document.Root.Add(elements);
|
||||
|
||||
using (var stream = _virtualPathProvider.CreateText(persistancePath)) {
|
||||
document.Save(stream, SaveOptions.None);
|
||||
}
|
||||
|
||||
// Ensure cache is invalidated right away, not waiting for file change notification to happen
|
||||
_token.IsCurrent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public class WebFormsExtensionsVirtualFile : VirtualFile {
|
||||
private readonly DependencyDescriptor _dependencyDescriptor;
|
||||
private readonly VirtualFile _actualFile;
|
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public class WebFormsExtensionsVirtualPathProvider : VirtualPathProvider, ICustomVirtualPathProvider {
|
||||
private readonly IDependenciesFolder _dependenciesFolder;
|
||||
private readonly string[] _prefixes = { "~/Modules/", "/Modules/" };
|
113
src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs
Normal file
113
src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Caching;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
public class DefaultVirtualPathMonitor : IVirtualPathMonitor {
|
||||
private readonly Thunk _thunk;
|
||||
private readonly string _prefix = Guid.NewGuid().ToString("n");
|
||||
private readonly IDictionary<string, Weak<Token>> _tokens = new Dictionary<string, Weak<Token>>();
|
||||
private readonly IClock _clock;
|
||||
|
||||
public DefaultVirtualPathMonitor(IClock clock) {
|
||||
_clock = clock;
|
||||
_thunk = new Thunk(this);
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string virtualPath) {
|
||||
// Fix this to monitor first existing parent directory.
|
||||
var token = BindToken(virtualPath);
|
||||
BindSignal(virtualPath);
|
||||
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;
|
||||
if (!_tokens.TryGetValue(virtualPath, out weak)) {
|
||||
weak = new Weak<Token>(new Token(virtualPath));
|
||||
_tokens[virtualPath] = weak;
|
||||
}
|
||||
|
||||
var token = weak.Target;
|
||||
if (token == null) {
|
||||
token = new Token(virtualPath);
|
||||
weak.Target = token;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
private Token DetachToken(string virtualPath) {
|
||||
lock (_tokens) {
|
||||
Weak<Token> weak;
|
||||
if (!_tokens.TryGetValue(virtualPath, out weak)) {
|
||||
return null;
|
||||
}
|
||||
var token = weak.Target;
|
||||
weak.Target = null;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
private void BindSignal(string virtualPath) {
|
||||
BindSignal(virtualPath, _thunk.Signal);
|
||||
|
||||
}
|
||||
|
||||
private void BindSignal(string virtualPath, CacheItemRemovedCallback callback) {
|
||||
var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency(
|
||||
virtualPath,
|
||||
new[] { virtualPath },
|
||||
_clock.UtcNow);
|
||||
|
||||
HostingEnvironment.Cache.Add(
|
||||
_prefix + virtualPath,
|
||||
virtualPath,
|
||||
cacheDependency,
|
||||
Cache.NoAbsoluteExpiration,
|
||||
Cache.NoSlidingExpiration,
|
||||
CacheItemPriority.NotRemovable,
|
||||
callback);
|
||||
}
|
||||
|
||||
public void Signal(string key, object value, CacheItemRemovedReason reason) {
|
||||
var virtualPath = Convert.ToString(value);
|
||||
var token = DetachToken(virtualPath);
|
||||
if (token != null)
|
||||
token.IsCurrent = false;
|
||||
}
|
||||
|
||||
public class Token : IVolatileToken {
|
||||
public Token(string virtualPath) {
|
||||
IsCurrent = true;
|
||||
VirtualPath = virtualPath;
|
||||
}
|
||||
public bool IsCurrent { get; set; }
|
||||
public string VirtualPath { get; private set; }
|
||||
}
|
||||
|
||||
class Thunk {
|
||||
private readonly Weak<DefaultVirtualPathMonitor> _weak;
|
||||
|
||||
public Thunk(DefaultVirtualPathMonitor provider) {
|
||||
_weak = new Weak<DefaultVirtualPathMonitor>(provider);
|
||||
}
|
||||
|
||||
public void Signal(string key, object value, CacheItemRemovedReason reason) {
|
||||
var provider = _weak.Target;
|
||||
if (provider != null)
|
||||
provider.Signal(key, value, reason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,26 +1,14 @@
|
||||
using System.IO;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IVirtualPathProvider : IVolatileProvider {
|
||||
string GetDirectoryName(string virtualPath);
|
||||
string Combine(params string[] paths);
|
||||
Stream OpenFile(string virtualPath);
|
||||
StreamWriter CreateText(string virtualPath);
|
||||
string MapPath(string virtualPath);
|
||||
bool FileExists(string virtualPath);
|
||||
bool DirectoryExists(string virtualPath);
|
||||
void CreateDirectory(string virtualPath);
|
||||
}
|
||||
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
public class DefaultVirtualPathProvider : IVirtualPathProvider {
|
||||
public string GetDirectoryName(string virtualPath) {
|
||||
return Path.GetDirectoryName(virtualPath).Replace('\\', '/');
|
||||
return Path.GetDirectoryName(virtualPath).Replace(Path.DirectorySeparatorChar, '/');
|
||||
}
|
||||
|
||||
public string Combine(params string[] paths) {
|
||||
return Path.Combine(paths).Replace('\\', '/');
|
||||
return Path.Combine(paths).Replace(Path.DirectorySeparatorChar, '/');
|
||||
}
|
||||
|
||||
public Stream OpenFile(string virtualPath) {
|
@@ -1,6 +1,6 @@
|
||||
using System.Web.Hosting;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
public interface ICustomVirtualPathProvider {
|
||||
VirtualPathProvider Instance { get; }
|
||||
}
|
15
src/Orchard/FileSystems/VirtualPath/IVirtualPathMonitor.cs
Normal file
15
src/Orchard/FileSystems/VirtualPath/IVirtualPathMonitor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
/// <summary>
|
||||
/// Enable monitoring changes over virtual path
|
||||
/// </summary>
|
||||
public interface IVirtualPathMonitor : IVolatileProvider {
|
||||
IVolatileToken WhenPathChanges(string virtualPath);
|
||||
// Temporary until we have a generic mechanism for components
|
||||
// to synchronize their dependencies through a Context.Monitor()
|
||||
// interface
|
||||
void WhenPathChanges(string virtualPath, Action action);
|
||||
}
|
||||
}
|
17
src/Orchard/FileSystems/VirtualPath/IVirtualPathProvider.cs
Normal file
17
src/Orchard/FileSystems/VirtualPath/IVirtualPathProvider.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.IO;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
public interface IVirtualPathProvider : IVolatileProvider {
|
||||
string Combine(params string[] paths);
|
||||
string MapPath(string virtualPath);
|
||||
|
||||
bool FileExists(string virtualPath);
|
||||
Stream OpenFile(string virtualPath);
|
||||
StreamWriter CreateText(string virtualPath);
|
||||
|
||||
bool DirectoryExists(string virtualPath);
|
||||
void CreateDirectory(string virtualPath);
|
||||
string GetDirectoryName(string virtualPath);
|
||||
}
|
||||
}
|
@@ -3,11 +3,14 @@ using System.Collections.Generic;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.FileSystems.WebSite {
|
||||
/// <summary>
|
||||
/// Abstraction over the virtual files/directories of a web site.
|
||||
/// </summary>
|
||||
public interface IWebSiteFolder : IVolatileProvider {
|
||||
IEnumerable<string> ListDirectories(string path);
|
||||
string ReadFile(string path);
|
||||
IEnumerable<string> ListDirectories(string virtualPath);
|
||||
string ReadFile(string virtualPath);
|
||||
|
||||
IVolatileToken WhenPathChanges(string path);
|
||||
void WhenPathChanges(string path, Action action);
|
||||
IVolatileToken WhenPathChanges(string virtualPath);
|
||||
void WhenPathChanges(string virtualPath, Action action);
|
||||
}
|
||||
}
|
@@ -2,22 +2,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Caching;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Services;
|
||||
using Orchard.Environment;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.FileSystems.WebSite {
|
||||
public class WebSiteFolder : IWebSiteFolder {
|
||||
private readonly IClock _clock;
|
||||
private readonly Thunk _thunk;
|
||||
private readonly string _prefix = Guid.NewGuid().ToString("n");
|
||||
private readonly IDictionary<string, Weak<Token>> _tokens = new Dictionary<string, Weak<Token>>();
|
||||
private readonly IVirtualPathMonitor _virtualPathMonitor;
|
||||
|
||||
|
||||
public WebSiteFolder(IClock clock) {
|
||||
_clock = clock;
|
||||
_thunk = new Thunk(this);
|
||||
public WebSiteFolder(IVirtualPathMonitor virtualPathMonitor) {
|
||||
_virtualPathMonitor = virtualPathMonitor;
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListDirectories(string virtualPath) {
|
||||
@@ -43,95 +38,11 @@ namespace Orchard.FileSystems.WebSite {
|
||||
}
|
||||
|
||||
public IVolatileToken WhenPathChanges(string virtualPath) {
|
||||
// Fix this to monitor first existing parent directory.
|
||||
var token = BindToken(virtualPath);
|
||||
BindSignal(virtualPath);
|
||||
return token;
|
||||
return _virtualPathMonitor.WhenPathChanges(virtualPath);
|
||||
}
|
||||
|
||||
public void WhenPathChanges(string virtualPath, Action action) {
|
||||
BindSignal(virtualPath, (key, value, reason) => action());
|
||||
}
|
||||
|
||||
private Token BindToken(string virtualPath) {
|
||||
lock (_tokens) {
|
||||
Weak<Token> weak;
|
||||
if (!_tokens.TryGetValue(virtualPath, out weak)) {
|
||||
weak = new Weak<Token>(new Token(virtualPath));
|
||||
_tokens[virtualPath] = weak;
|
||||
}
|
||||
|
||||
var token = weak.Target;
|
||||
if (token == null) {
|
||||
token = new Token(virtualPath);
|
||||
weak.Target = token;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
private Token DetachToken(string virtualPath) {
|
||||
lock (_tokens) {
|
||||
Weak<Token> weak;
|
||||
if (!_tokens.TryGetValue(virtualPath, out weak)) {
|
||||
return null;
|
||||
}
|
||||
var token = weak.Target;
|
||||
weak.Target = null;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
private void BindSignal(string virtualPath) {
|
||||
BindSignal(virtualPath, _thunk.Signal);
|
||||
|
||||
}
|
||||
|
||||
private void BindSignal(string virtualPath, CacheItemRemovedCallback callback) {
|
||||
var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency(
|
||||
virtualPath,
|
||||
new[] { virtualPath },
|
||||
_clock.UtcNow);
|
||||
|
||||
HostingEnvironment.Cache.Add(
|
||||
_prefix + virtualPath,
|
||||
virtualPath,
|
||||
cacheDependency,
|
||||
Cache.NoAbsoluteExpiration,
|
||||
Cache.NoSlidingExpiration,
|
||||
CacheItemPriority.NotRemovable,
|
||||
callback);
|
||||
}
|
||||
|
||||
public void Signal(string key, object value, CacheItemRemovedReason reason) {
|
||||
var virtualPath = Convert.ToString(value);
|
||||
var token = DetachToken(virtualPath);
|
||||
if (token != null)
|
||||
token.IsCurrent = false;
|
||||
}
|
||||
|
||||
public class Token : IVolatileToken {
|
||||
public Token(string virtualPath) {
|
||||
IsCurrent = true;
|
||||
VirtualPath = virtualPath;
|
||||
}
|
||||
public bool IsCurrent { get; set; }
|
||||
public string VirtualPath { get; private set; }
|
||||
}
|
||||
|
||||
class Thunk {
|
||||
private readonly Weak<WebSiteFolder> _weak;
|
||||
|
||||
public Thunk(WebSiteFolder provider) {
|
||||
_weak = new Weak<WebSiteFolder>(provider);
|
||||
}
|
||||
|
||||
public void Signal(string key, object value, CacheItemRemovedReason reason) {
|
||||
var provider = _weak.Target;
|
||||
if (provider != null)
|
||||
provider.Signal(key, value, reason);
|
||||
}
|
||||
_virtualPathMonitor.WhenPathChanges(virtualPath, action);
|
||||
}
|
||||
}
|
||||
}
|
@@ -353,11 +353,15 @@
|
||||
<Compile Include="Data\Orderable.cs" />
|
||||
<Compile Include="Environment\DefaultOrchardShell.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\MergedReadOnlyStreams.cs" />
|
||||
<Compile Include="Environment\ICustomVirtualPathProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualPathProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualFile.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\DefaultDependenciesFolder.cs" />
|
||||
<Compile Include="FileSystems\VirtualPath\DefaultVirtualPathMonitor.cs" />
|
||||
<Compile Include="FileSystems\VirtualPath\DefaultVirtualPathProvider.cs" />
|
||||
<Compile Include="FileSystems\VirtualPath\ICustomVirtualPathProvider.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\WebFormsExtensionsVirtualPathProvider.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\WebFormsExtensionsVirtualFile.cs" />
|
||||
<Compile Include="Environment\Extensions\IExtensionManagerEvents.cs" />
|
||||
<Compile Include="Environment\IHostEnvironment.cs" />
|
||||
<Compile Include="FileSystems\VirtualPath\IVirtualPathMonitor.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpExtensionBuildProvider.cs" />
|
||||
@@ -367,7 +371,7 @@
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpProjectParser.cs" />
|
||||
<Compile Include="Environment\IAssemblyBuilder.cs" />
|
||||
<Compile Include="Environment\IBuildManager.cs" />
|
||||
<Compile Include="Environment\IVirtualPathProvider.cs" />
|
||||
<Compile Include="FileSystems\VirtualPath\IVirtualPathProvider.cs" />
|
||||
<Compile Include="Environment\IOrchardShell.cs" />
|
||||
<Compile Include="Environment\OrchardStarter.cs" />
|
||||
<Compile Include="Environment\State\DefaultProcessingEngine.cs" />
|
||||
|
Reference in New Issue
Block a user