mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-19 18:27:55 +08:00
Tweak dynamic extension loader
* Add "Assembly Src" directive to WebForms files loaded from vpp * Notify the OrchardHost when the .csproj file a a dynamic module is changed. * Make the registration of custom virtual path provider a bit more extensible, so that the custom VPP can be instantiated using DI. --HG-- branch : dev
This commit is contained in:
@@ -31,7 +31,6 @@ namespace Orchard.Web {
|
|||||||
|
|
||||||
RegisterRoutes(RouteTable.Routes);
|
RegisterRoutes(RouteTable.Routes);
|
||||||
|
|
||||||
HostingEnvironment.RegisterVirtualPathProvider(new WebFormsExtensionsVirtualPathProvider());
|
|
||||||
_host = OrchardStarter.CreateHost(MvcSingletons);
|
_host = OrchardStarter.CreateHost(MvcSingletons);
|
||||||
_host.Initialize();
|
_host.Initialize();
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ using Orchard.Mvc.ViewEngines;
|
|||||||
using Orchard.Utility.Extensions;
|
using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
namespace Orchard.Environment {
|
namespace Orchard.Environment {
|
||||||
public class DefaultOrchardHost : IOrchardHost, IShellSettingsManagerEventHandler, IShellDescriptorManagerEventHandler {
|
public class DefaultOrchardHost : IOrchardHost, IShellSettingsManagerEventHandler, IShellDescriptorManagerEventHandler, IExtensionManagerEvents {
|
||||||
private readonly ControllerBuilder _controllerBuilder;
|
private readonly ControllerBuilder _controllerBuilder;
|
||||||
|
|
||||||
private readonly IShellSettingsManager _shellSettingsManager;
|
private readonly IShellSettingsManager _shellSettingsManager;
|
||||||
@@ -147,5 +147,9 @@ namespace Orchard.Environment {
|
|||||||
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) {
|
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) {
|
||||||
_current = null;
|
_current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IExtensionManagerEvents.ModuleChanged(string moduleName) {
|
||||||
|
_current = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Web.Compilation;
|
using System.Diagnostics;
|
||||||
|
using System.Web.Compilation;
|
||||||
|
|
||||||
namespace Orchard.Environment.Extensions.Compilers {
|
namespace Orchard.Environment.Extensions.Compilers {
|
||||||
public class CSharpExtensionBuildProvider : BuildProvider {
|
public class CSharpExtensionBuildProvider : BuildProvider {
|
||||||
@@ -11,6 +12,10 @@ namespace Orchard.Environment.Extensions.Compilers {
|
|||||||
public override CompilerType CodeCompilerType { get { return _codeCompilerType; } }
|
public override CompilerType CodeCompilerType { get { return _codeCompilerType; } }
|
||||||
|
|
||||||
public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
|
public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
|
||||||
|
//Debug.WriteLine(string.Format("BuildProvider for file \"{0}\"", this.VirtualPath));
|
||||||
|
|
||||||
|
//TODO: It probably would be better to access the OrchardHost container
|
||||||
|
// to resolve these dependencies.
|
||||||
var virtualPathProvider = new DefaultVirtualPathProvider();
|
var virtualPathProvider = new DefaultVirtualPathProvider();
|
||||||
var compiler = new CSharpProjectMediumTrustCompiler(virtualPathProvider);
|
var compiler = new CSharpProjectMediumTrustCompiler(virtualPathProvider);
|
||||||
|
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
using Orchard.Events;
|
||||||
|
|
||||||
|
namespace Orchard.Environment.Extensions {
|
||||||
|
public interface IExtensionManagerEvents : IEventHandler {
|
||||||
|
void ModuleChanged(string moduleName);
|
||||||
|
}
|
||||||
|
}
|
@@ -28,7 +28,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
var assembly = _buildManager.GetCompiledAssembly(projectPath);
|
var assembly = _buildManager.GetCompiledAssembly(projectPath);
|
||||||
|
|
||||||
if (_hostEnvironment.IsFullTrust) {
|
if (_hostEnvironment.IsFullTrust) {
|
||||||
_dependenciesFolder.StoreAssemblyFile(descriptor.Name, assembly.Location);
|
_dependenciesFolder.StoreBuildProviderAssembly(descriptor.Name, projectPath, assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExtensionEntry {
|
return new ExtensionEntry {
|
||||||
|
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Orchard.Environment.Extensions.Loaders {
|
||||||
|
/// <summary>
|
||||||
|
/// Expose a read-only stream as the concatenation of a list of read-only streams
|
||||||
|
/// </summary>
|
||||||
|
public class MergedReadOnlyStreams : Stream {
|
||||||
|
private class StreamDescriptor {
|
||||||
|
public int Index { get; set; }
|
||||||
|
public Stream Stream { get; set; }
|
||||||
|
public long Offset { get; set; }
|
||||||
|
public long Length { get; set; }
|
||||||
|
public long Limit { get { return Offset + Length; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<StreamDescriptor> _streams;
|
||||||
|
private long _position;
|
||||||
|
|
||||||
|
public MergedReadOnlyStreams(params Stream[] streams) {
|
||||||
|
_streams = CreateDescritors(streams).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<StreamDescriptor> CreateDescritors(params Stream[] streams) {
|
||||||
|
long offset = 0;
|
||||||
|
int index = 0;
|
||||||
|
foreach (var stream in streams) {
|
||||||
|
yield return new StreamDescriptor {
|
||||||
|
Stream = stream,
|
||||||
|
Index = index,
|
||||||
|
Length = stream.Length,
|
||||||
|
Offset = offset
|
||||||
|
};
|
||||||
|
|
||||||
|
offset += stream.Length;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void Flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin) {
|
||||||
|
switch (origin) {
|
||||||
|
case SeekOrigin.Begin:
|
||||||
|
_position = offset;
|
||||||
|
break;
|
||||||
|
case SeekOrigin.Current:
|
||||||
|
_position += offset;
|
||||||
|
break;
|
||||||
|
case SeekOrigin.End:
|
||||||
|
_position = Length + offset;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException("origin");
|
||||||
|
}
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count) {
|
||||||
|
int totalRead = 0;
|
||||||
|
while (count > 0) {
|
||||||
|
// Find stream for current position (might fail if end of all streams)
|
||||||
|
var descriptor = GetDescriptor(_position);
|
||||||
|
if (descriptor == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Read bytes from the current stream
|
||||||
|
int read = descriptor.Stream.Read(buffer, offset, count);
|
||||||
|
if (read == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_position += read;
|
||||||
|
totalRead += read;
|
||||||
|
count -= read;
|
||||||
|
offset += read;
|
||||||
|
}
|
||||||
|
return totalRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StreamDescriptor GetDescriptor(long position) {
|
||||||
|
return _streams.SingleOrDefault(stream => stream.Offset <= position && position < stream.Limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek {
|
||||||
|
get { return _streams.All(d => d.Stream.CanSeek); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length {
|
||||||
|
get { return _streams.Aggregate(0L, (prev, desc) => prev + desc.Length); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position {
|
||||||
|
get { return _position; }
|
||||||
|
set {
|
||||||
|
if (!CanSeek)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
_position = Position;
|
||||||
|
|
||||||
|
// Update the position of all streams
|
||||||
|
foreach(var desc in _streams) {
|
||||||
|
if (_position < desc.Offset) desc.Stream.Position = 0;
|
||||||
|
else if (_position > desc.Limit) desc.Stream.Position = desc.Stream.Length;
|
||||||
|
else desc.Stream.Position = _position - desc.Offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
if (!_virtualPathProvider.FileExists(extensionPath))
|
if (!_virtualPathProvider.FileExists(extensionPath))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
_folder.StoreAssemblyFile(descriptor.Name, _virtualPathProvider.MapPath(extensionPath));
|
_folder.StorePrecompiledAssembly(descriptor.Name, extensionPath);
|
||||||
|
|
||||||
var assembly = _folder.LoadAssembly(descriptor.Name);
|
var assembly = _folder.LoadAssembly(descriptor.Name);
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using System.Web.Hosting;
|
using System.Web.Hosting;
|
||||||
|
using Orchard.FileSystems.Dependencies;
|
||||||
|
|
||||||
namespace Orchard.Environment.Extensions.Loaders {
|
namespace Orchard.Environment.Extensions.Loaders {
|
||||||
public class WebFormsExtensionsVirtualFile : VirtualFile {
|
public class WebFormsExtensionsVirtualFile : VirtualFile {
|
||||||
private readonly Assembly _assembly;
|
private readonly DependencyDescriptor _dependencyDescriptor;
|
||||||
private readonly VirtualFile _actualFile;
|
private readonly VirtualFile _actualFile;
|
||||||
|
|
||||||
public WebFormsExtensionsVirtualFile(string virtualPath, Assembly assembly, VirtualFile actualFile)
|
public WebFormsExtensionsVirtualFile(string virtualPath, DependencyDescriptor dependencyDescriptor, VirtualFile actualFile)
|
||||||
: base(virtualPath) {
|
: base(virtualPath) {
|
||||||
_assembly = assembly;
|
_dependencyDescriptor = dependencyDescriptor;
|
||||||
_actualFile = actualFile;
|
_actualFile = actualFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,9 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Stream Open() {
|
public override Stream Open() {
|
||||||
var reader = new StreamReader(_actualFile.Open());
|
using (var actualStream = _actualFile.Open()) {
|
||||||
|
var reader = new StreamReader(actualStream);
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
int length;
|
int length;
|
||||||
using (var writer = new StreamWriter(memoryStream)) {
|
using (var writer = new StreamWriter(memoryStream)) {
|
||||||
@@ -35,7 +37,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) {
|
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) {
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(line) && !assemblyDirectiveAdded) {
|
if (!string.IsNullOrWhiteSpace(line) && !assemblyDirectiveAdded) {
|
||||||
line += string.Format("<%@ Assembly Name=\"{0}\"%>", _assembly);
|
line += GetAssemblyDirective();
|
||||||
assemblyDirectiveAdded = true;
|
assemblyDirectiveAdded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +46,17 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
writer.Flush();
|
writer.Flush();
|
||||||
length = (int) memoryStream.Length;
|
length = (int) memoryStream.Length;
|
||||||
}
|
}
|
||||||
var result = new MemoryStream(memoryStream.GetBuffer(), 0, length);
|
return new MemoryStream(memoryStream.GetBuffer(), 0, length);
|
||||||
return result;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAssemblyDirective() {
|
||||||
|
if (_dependencyDescriptor.IsFromBuildProvider) {
|
||||||
|
return string.Format("<%@ Assembly Src=\"{0}\"%>", _dependencyDescriptor.VirtualPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return string.Format("<%@ Assembly Name=\"{0}\"%>", _dependencyDescriptor.ModuleName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,17 +4,13 @@ using System.Web.Hosting;
|
|||||||
using Orchard.FileSystems.Dependencies;
|
using Orchard.FileSystems.Dependencies;
|
||||||
|
|
||||||
namespace Orchard.Environment.Extensions.Loaders {
|
namespace Orchard.Environment.Extensions.Loaders {
|
||||||
public class WebFormsExtensionsVirtualPathProvider : VirtualPathProvider {
|
public class WebFormsExtensionsVirtualPathProvider : VirtualPathProvider, ICustomVirtualPathProvider {
|
||||||
private IDependenciesFolder _dependenciesFolder;
|
private readonly IDependenciesFolder _dependenciesFolder;
|
||||||
private const string _prefix1 = "~/Modules/";
|
private readonly string[] _prefixes = { "~/Modules/", "/Modules/" };
|
||||||
private const string _prefix2 = "/Modules/";
|
private readonly string[] _extensions = { ".ascx", ".aspx", ".master" };
|
||||||
|
|
||||||
public WebFormsExtensionsVirtualPathProvider() {
|
public WebFormsExtensionsVirtualPathProvider(IDependenciesFolder dependenciesFolder) {
|
||||||
}
|
_dependenciesFolder = dependenciesFolder;
|
||||||
|
|
||||||
protected override void Initialize() {
|
|
||||||
base.Initialize();
|
|
||||||
_dependenciesFolder = new DefaultDependenciesFolder(new DefaultVirtualPathProvider());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool DirectoryExists(string virtualDir) {
|
public override bool DirectoryExists(string virtualDir) {
|
||||||
@@ -28,11 +24,11 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
public override VirtualFile GetFile(string virtualPath) {
|
public override VirtualFile GetFile(string virtualPath) {
|
||||||
var actualFile = Previous.GetFile(virtualPath);
|
var actualFile = Previous.GetFile(virtualPath);
|
||||||
|
|
||||||
var prefix = PrefixMatch(virtualPath);
|
var prefix = PrefixMatch(virtualPath, _prefixes);
|
||||||
if (prefix == null)
|
if (prefix == null)
|
||||||
return actualFile;
|
return actualFile;
|
||||||
|
|
||||||
var extension = ExtensionMatch(virtualPath, ".ascx", ".aspx", ".master");
|
var extension = ExtensionMatch(virtualPath, _extensions);
|
||||||
if (extension == null)
|
if (extension == null)
|
||||||
return actualFile;
|
return actualFile;
|
||||||
|
|
||||||
@@ -42,13 +38,13 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
|
|
||||||
// It looks like we have a module name. Is this one of this modules
|
// It looks like we have a module name. Is this one of this modules
|
||||||
// with its assembly stored in the "App_Data/Dependencies" folder?
|
// with its assembly stored in the "App_Data/Dependencies" folder?
|
||||||
var assembly = _dependenciesFolder.LoadAssembly(moduleName);
|
var dependencyDescriptor = _dependenciesFolder.GetDescriptor(moduleName);
|
||||||
if (assembly == null)
|
if (dependencyDescriptor == null)
|
||||||
return actualFile;
|
return actualFile;
|
||||||
|
|
||||||
// Yes: we need to wrap the VirtualFile to add the <%@ Assembly Name=".."%> directive
|
// Yes: we need to wrap the VirtualFile to add the <%@ Assembly Name=".."%> directive
|
||||||
// in the content.
|
// in the content.
|
||||||
return new WebFormsExtensionsVirtualFile(virtualPath, assembly, actualFile);
|
return new WebFormsExtensionsVirtualFile(virtualPath, dependencyDescriptor, actualFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ModuleMatch(string virtualPath, string prefix) {
|
private string ModuleMatch(string virtualPath, string prefix) {
|
||||||
@@ -65,13 +61,13 @@ namespace Orchard.Environment.Extensions.Loaders {
|
|||||||
.FirstOrDefault(e => virtualPath.EndsWith(e, StringComparison.OrdinalIgnoreCase));
|
.FirstOrDefault(e => virtualPath.EndsWith(e, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string PrefixMatch(string virtualPath) {
|
private string PrefixMatch(string virtualPath, params string[] prefixes) {
|
||||||
if (virtualPath.StartsWith(_prefix1))
|
return prefixes
|
||||||
return _prefix1;
|
.FirstOrDefault(p => virtualPath.StartsWith(p, StringComparison.OrdinalIgnoreCase));
|
||||||
if (virtualPath.StartsWith(_prefix2))
|
}
|
||||||
return _prefix2;
|
|
||||||
return null;
|
|
||||||
|
|
||||||
|
VirtualPathProvider ICustomVirtualPathProvider.Instance {
|
||||||
|
get { return this; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
7
src/Orchard/Environment/ICustomVirtualPathProvider.cs
Normal file
7
src/Orchard/Environment/ICustomVirtualPathProvider.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using System.Web.Hosting;
|
||||||
|
|
||||||
|
namespace Orchard.Environment {
|
||||||
|
public interface ICustomVirtualPathProvider {
|
||||||
|
VirtualPathProvider Instance { get; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Web.Hosting;
|
using System.Web.Hosting;
|
||||||
@@ -33,6 +34,7 @@ namespace Orchard.Environment {
|
|||||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||||
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();
|
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();
|
||||||
|
builder.RegisterType<WebFormsExtensionsVirtualPathProvider>().As<ICustomVirtualPathProvider>().SingleInstance();
|
||||||
|
|
||||||
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
|
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
|
||||||
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
|
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
|
||||||
@@ -117,6 +119,15 @@ namespace Orchard.Environment {
|
|||||||
|
|
||||||
public static IOrchardHost CreateHost(Action<ContainerBuilder> registrations) {
|
public static IOrchardHost CreateHost(Action<ContainerBuilder> registrations) {
|
||||||
var container = CreateHostContainer(registrations);
|
var container = CreateHostContainer(registrations);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register Virtual Path Providers
|
||||||
|
//
|
||||||
|
foreach (var vpp in container.Resolve<IEnumerable<ICustomVirtualPathProvider>>()) {
|
||||||
|
HostingEnvironment.RegisterVirtualPathProvider(vpp.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return container.Resolve<IOrchardHost>();
|
return container.Resolve<IOrchardHost>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,40 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Web.Caching;
|
||||||
|
using System.Web.Hosting;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Orchard.Caching;
|
using Orchard.Caching;
|
||||||
using Orchard.Environment;
|
using Orchard.Environment;
|
||||||
|
using Orchard.Environment.Extensions;
|
||||||
|
using Orchard.Environment.Topology;
|
||||||
|
|
||||||
namespace Orchard.FileSystems.Dependencies {
|
namespace Orchard.FileSystems.Dependencies {
|
||||||
|
public class DependencyDescriptor {
|
||||||
|
public string ModuleName { get; set; }
|
||||||
|
public bool IsFromBuildProvider { get; set; }
|
||||||
|
public string VirtualPath { get; set; }
|
||||||
|
public string FileName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public interface IDependenciesFolder : IVolatileProvider {
|
public interface IDependenciesFolder : IVolatileProvider {
|
||||||
void StoreAssemblyFile(string assemblyName, string assemblyFileName);
|
void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly);
|
||||||
|
void StorePrecompiledAssembly(string moduleName, string virtualPath);
|
||||||
|
DependencyDescriptor GetDescriptor(string moduleName);
|
||||||
Assembly LoadAssembly(string assemblyName);
|
Assembly LoadAssembly(string assemblyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultDependenciesFolder : IDependenciesFolder {
|
public class DefaultDependenciesFolder : IDependenciesFolder {
|
||||||
|
private readonly string _prefix = Guid.NewGuid().ToString("n");
|
||||||
private const string _basePath = "~/App_Data/Dependencies";
|
private const string _basePath = "~/App_Data/Dependencies";
|
||||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||||
|
private readonly IExtensionManagerEvents _events;
|
||||||
|
|
||||||
public DefaultDependenciesFolder(IVirtualPathProvider virtualPathProvider) {
|
public DefaultDependenciesFolder(IVirtualPathProvider virtualPathProvider, IExtensionManagerEvents events) {
|
||||||
_virtualPathProvider = virtualPathProvider;
|
_virtualPathProvider = virtualPathProvider;
|
||||||
|
_events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BasePath {
|
private string BasePath {
|
||||||
@@ -32,21 +49,60 @@ namespace Orchard.FileSystems.Dependencies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StoreAssemblyFile(string assemblyName, string assemblyFileName) {
|
public void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly) {
|
||||||
|
_virtualPathProvider.CreateDirectory(BasePath);
|
||||||
|
|
||||||
|
var descriptor = new DependencyDescriptor {
|
||||||
|
ModuleName = moduleName,
|
||||||
|
IsFromBuildProvider = true,
|
||||||
|
VirtualPath = virtualPath,
|
||||||
|
FileName = assembly.Location
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StorePrecompiledAssembly(string moduleName, string virtualPath) {
|
||||||
_virtualPathProvider.CreateDirectory(BasePath);
|
_virtualPathProvider.CreateDirectory(BasePath);
|
||||||
|
|
||||||
// Only store assembly if it's more recent that what we have stored already (if anything)
|
// Only store assembly if it's more recent that what we have stored already (if anything)
|
||||||
if (IsNewerAssembly(assemblyName, assemblyFileName)) {
|
var assemblyFileName = _virtualPathProvider.MapPath(virtualPath);
|
||||||
|
if (IsNewerAssembly(moduleName, assemblyFileName)) {
|
||||||
var destinationFileName = Path.GetFileName(assemblyFileName);
|
var destinationFileName = Path.GetFileName(assemblyFileName);
|
||||||
var destinationPath = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, destinationFileName));
|
var destinationPath = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, destinationFileName));
|
||||||
File.Copy(assemblyFileName, destinationPath, true);
|
File.Copy(assemblyFileName, destinationPath, true);
|
||||||
|
|
||||||
StoreDepencyInformation(assemblyName, destinationFileName);
|
StoreDepencyInformation(new DependencyDescriptor {
|
||||||
|
ModuleName = moduleName,
|
||||||
|
IsFromBuildProvider = false,
|
||||||
|
VirtualPath = virtualPath,
|
||||||
|
FileName = destinationFileName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsNewerAssembly(string assemblyName, string assemblyFileName) {
|
public DependencyDescriptor GetDescriptor(string moduleName) {
|
||||||
var dependency = ReadDependencies().SingleOrDefault(d => d.Name == assemblyName);
|
return ReadDependencies().SingleOrDefault(d => d.ModuleName == moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsNewerAssembly(string moduleName, string assemblyFileName) {
|
||||||
|
var dependency = ReadDependencies().SingleOrDefault(d => d.ModuleName == moduleName);
|
||||||
if (dependency == null) {
|
if (dependency == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -59,15 +115,15 @@ namespace Orchard.FileSystems.Dependencies {
|
|||||||
return (File.GetLastWriteTimeUtc(existingFileName) < File.GetLastWriteTimeUtc(assemblyFileName));
|
return (File.GetLastWriteTimeUtc(existingFileName) < File.GetLastWriteTimeUtc(assemblyFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StoreDepencyInformation(string name, string fileName) {
|
private void StoreDepencyInformation(DependencyDescriptor descriptor) {
|
||||||
var dependencies = ReadDependencies().ToList();
|
var dependencies = ReadDependencies().ToList();
|
||||||
|
int index = dependencies.FindIndex(d => d.ModuleName == descriptor.ModuleName);
|
||||||
var dependency = dependencies.SingleOrDefault(d => d.Name == name);
|
if (index < 0) {
|
||||||
if (dependency == null) {
|
dependencies.Add(descriptor);
|
||||||
dependency = new DependencyDescritpor { Name = name, FileName = fileName };
|
}
|
||||||
dependencies.Add(dependency);
|
else {
|
||||||
|
dependencies[index] = descriptor;
|
||||||
}
|
}
|
||||||
dependency.FileName = fileName;
|
|
||||||
|
|
||||||
WriteDependencies(dependencies);
|
WriteDependencies(dependencies);
|
||||||
}
|
}
|
||||||
@@ -75,7 +131,7 @@ namespace Orchard.FileSystems.Dependencies {
|
|||||||
public Assembly LoadAssembly(string assemblyName) {
|
public Assembly LoadAssembly(string assemblyName) {
|
||||||
_virtualPathProvider.CreateDirectory(BasePath);
|
_virtualPathProvider.CreateDirectory(BasePath);
|
||||||
|
|
||||||
var dependency = ReadDependencies().SingleOrDefault(d => d.Name == assemblyName);
|
var dependency = ReadDependencies().SingleOrDefault(d => d.ModuleName == assemblyName);
|
||||||
if (dependency == null)
|
if (dependency == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -85,30 +141,32 @@ namespace Orchard.FileSystems.Dependencies {
|
|||||||
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
|
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DependencyDescritpor {
|
private IEnumerable<DependencyDescriptor> ReadDependencies() {
|
||||||
public string Name { get; set; }
|
|
||||||
public string FileName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<DependencyDescritpor> ReadDependencies() {
|
|
||||||
if (!_virtualPathProvider.FileExists(PersistencePath))
|
if (!_virtualPathProvider.FileExists(PersistencePath))
|
||||||
return Enumerable.Empty<DependencyDescritpor>();
|
return Enumerable.Empty<DependencyDescriptor>();
|
||||||
|
|
||||||
using (var stream = _virtualPathProvider.OpenFile(PersistencePath)) {
|
using (var stream = _virtualPathProvider.OpenFile(PersistencePath)) {
|
||||||
XDocument document = XDocument.Load(stream);
|
XDocument document = XDocument.Load(stream);
|
||||||
return document
|
return document
|
||||||
.Elements(ns("Dependencies"))
|
.Elements(ns("Dependencies"))
|
||||||
.Elements(ns("Dependency"))
|
.Elements(ns("Dependency"))
|
||||||
.Select(e => new DependencyDescritpor { Name = e.Element("Name").Value, FileName = e.Element("FileName").Value })
|
.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();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteDependencies(IEnumerable<DependencyDescritpor> dependencies) {
|
private void WriteDependencies(IEnumerable<DependencyDescriptor> dependencies) {
|
||||||
var document = new XDocument();
|
var document = new XDocument();
|
||||||
document.Add(new XElement(ns("Dependencies")));
|
document.Add(new XElement(ns("Dependencies")));
|
||||||
var elements = dependencies.Select(d => new XElement("Dependency",
|
var elements = dependencies.Select(d => new XElement("Dependency",
|
||||||
new XElement(ns("Name"), d.Name),
|
new XElement(ns("ModuleName"), d.ModuleName),
|
||||||
|
new XElement(ns("VirtualPath"), d.VirtualPath),
|
||||||
|
new XElement(ns("IsFromBuildProvider"), d.IsFromBuildProvider),
|
||||||
new XElement(ns("FileName"), d.FileName)));
|
new XElement(ns("FileName"), d.FileName)));
|
||||||
document.Root.Add(elements);
|
document.Root.Add(elements);
|
||||||
|
|
||||||
|
@@ -341,8 +341,11 @@
|
|||||||
<Compile Include="Data\DataModule.cs" />
|
<Compile Include="Data\DataModule.cs" />
|
||||||
<Compile Include="Data\Orderable.cs" />
|
<Compile Include="Data\Orderable.cs" />
|
||||||
<Compile Include="Environment\DefaultOrchardShell.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\WebFormsExtensionsVirtualPathProvider.cs" />
|
||||||
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualFile.cs" />
|
<Compile Include="Environment\Extensions\Loaders\WebFormsExtensionsVirtualFile.cs" />
|
||||||
|
<Compile Include="Environment\Extensions\IExtensionManagerEvents.cs" />
|
||||||
<Compile Include="Environment\IHostEnvironment.cs" />
|
<Compile Include="Environment\IHostEnvironment.cs" />
|
||||||
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
|
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
|
||||||
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
|
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
|
||||||
|
Reference in New Issue
Block a user