mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Module loading strategies
Make the precompiled and dynamic extension loaders work properly and also refactor some code to introduce proper abstractions, such as IVirtualPathProvider, IHostEnvironment, IBuildManager, etc. --HG-- branch : dev
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
-->
|
||||
<compilation debug="true" targetFramework="4.0">
|
||||
<buildProviders>
|
||||
<add extension=".csproj" type="Orchard.Environment.Extensions.Loaders.CSharpExtensionBuildProvider"/>
|
||||
<add extension=".csproj" type="Orchard.Environment.Extensions.Compilers.CSharpExtensionBuildProvider"/>
|
||||
</buildProviders>
|
||||
<assemblies>
|
||||
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using System.Web.Compilation;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
public class CSharpExtensionBuildProvider : BuildProvider {
|
||||
private readonly CompilerType _codeCompilerType;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
public override CompilerType CodeCompilerType { get { return _codeCompilerType; } }
|
||||
|
||||
public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
|
||||
var virtualPathProvider = new AspNetVirtualPathProvider();
|
||||
var virtualPathProvider = new DefaultVirtualPathProvider();
|
||||
var compiler = new CSharpProjectMediumTrustCompiler(virtualPathProvider);
|
||||
|
||||
var aspNetAssemblyBuilder = new AspNetAssemblyBuilder(assemblyBuilder, this);
|
@@ -4,9 +4,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <summary>
|
||||
/// Compile a C# extension into an assembly given a directory location
|
||||
/// </summary>
|
@@ -1,9 +1,9 @@
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <summary>
|
||||
/// Compile a C# extension into an assembly given a directory location
|
||||
/// </summary>
|
||||
@@ -20,15 +20,17 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// Compile a csproj file given its virtual path. Use the CSharp CodeDomProvider
|
||||
/// class, which is only available in full trust.
|
||||
/// </summary>
|
||||
public CompilerResults CompileProject(string virtualPath) {
|
||||
public CompilerResults CompileProject(string virtualPath, string outputDirectory) {
|
||||
var codeProvider = CodeDomProvider.CreateProvider("cs");
|
||||
var directory = _virtualPathProvider.GetDirectoryName(virtualPath);
|
||||
|
||||
using (var stream = _virtualPathProvider.OpenFile(virtualPath)) {
|
||||
var descriptor = new CSharpProjectParser().Parse(stream);
|
||||
|
||||
var references = GetAssemblyReferenceNames();
|
||||
var references = GetReferencedAssembliesLocation();
|
||||
var options = new CompilerParameters(references.ToArray());
|
||||
options.GenerateExecutable = false;
|
||||
options.OutputAssembly = Path.Combine(outputDirectory, descriptor.AssemblyName + ".dll");
|
||||
|
||||
var fileNames = descriptor.SourceFilenames
|
||||
.Select(f => _virtualPathProvider.Combine(directory, f))
|
||||
@@ -39,11 +41,10 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAssemblyReferenceNames() {
|
||||
private IEnumerable<string> GetReferencedAssembliesLocation() {
|
||||
return _buildManager.GetReferencedAssemblies()
|
||||
.OfType<Assembly>()
|
||||
.Where(a => !string.IsNullOrEmpty(a.Location))
|
||||
.Select(a => a.Location)
|
||||
.Where(a => !string.IsNullOrEmpty(a))
|
||||
.Distinct();
|
||||
}
|
||||
}
|
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <summary>
|
||||
/// Compile a C# extension into an assembly given a directory location
|
||||
/// </summary>
|
@@ -4,25 +4,40 @@ using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
public class CSharpProjectDescriptor {
|
||||
public string AssemblyName { get; set; }
|
||||
public IEnumerable<string> SourceFilenames { get; set; }
|
||||
public IEnumerable<ReferenceDescriptor> References { get; set; }
|
||||
}
|
||||
|
||||
public class ReferenceDescriptor {
|
||||
public string AssemblyName { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return "{" + (AssemblyName ?? "") + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public class CSharpProjectParser {
|
||||
public CSharpProjectDescriptor Parse(Stream stream) {
|
||||
var document = XDocument.Load(XmlReader.Create(stream));
|
||||
return new CSharpProjectDescriptor {
|
||||
SourceFilenames = GetSourceFilenames(document),
|
||||
References = GetReferences(document)
|
||||
AssemblyName = GetAssemblyName(document),
|
||||
SourceFilenames = GetSourceFilenames(document).ToArray(),
|
||||
References = GetReferences(document).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
private string GetAssemblyName(XDocument document) {
|
||||
return document
|
||||
.Elements(ns("Project"))
|
||||
.Elements(ns("PropertyGroup"))
|
||||
.Elements(ns("AssemblyName"))
|
||||
.Single()
|
||||
.Value;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetSourceFilenames(XDocument document) {
|
||||
return document
|
||||
.Elements(ns("Project"))
|
@@ -5,7 +5,7 @@ using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
public class AreaExtensionLoader : IExtensionLoader {
|
||||
public int Order { get { return 5; } }
|
||||
public int Order { get { return 50; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
if (descriptor.Location == "~/Areas") {
|
||||
|
@@ -4,12 +4,14 @@ using System.Reflection;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
/// Load an extension by looking into specific namespaces of the "Orchard.Core" assembly
|
||||
/// </summary>
|
||||
public class CoreExtensionLoader : IExtensionLoader {
|
||||
public int Order { get { return 1; } }
|
||||
public int Order { get { return 10; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
if (descriptor.Location == "~/Core") {
|
||||
|
||||
var assembly = Assembly.Load("Orchard.Core");
|
||||
return new ExtensionEntry {
|
||||
Descriptor = descriptor,
|
||||
|
@@ -1,64 +1,36 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
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 {
|
||||
public class DynamicExtensionLoader : IExtensionLoader {
|
||||
public int Order { get { return 10; } }
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private readonly IBuildManager _buildManager;
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
private readonly IDependenciesFolder _dependenciesFolder;
|
||||
|
||||
public DynamicExtensionLoader(IHostEnvironment hostEnvironment, IBuildManager buildManager, IVirtualPathProvider virtualPathProvider, IDependenciesFolder dependenciesFolder) {
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_buildManager = buildManager;
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
_dependenciesFolder = dependenciesFolder;
|
||||
}
|
||||
|
||||
public int Order { get { return 100; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
if (HostingEnvironment.IsHosted == false)
|
||||
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name,
|
||||
descriptor.Name + ".csproj");
|
||||
if (!_virtualPathProvider.FileExists(projectPath)) {
|
||||
return null;
|
||||
|
||||
// 1) Try to load the assembly directory
|
||||
// This will look in the "App_Data/Dependencies" directory if
|
||||
// the probing path is correctly configured in Web.config
|
||||
{
|
||||
try {
|
||||
Assembly assembly = Assembly.Load(descriptor.Name);
|
||||
return CreateExtensionEntry(descriptor, assembly);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
// The assembly is not in one of the probing directory,
|
||||
// including "App_Data/Dependencies", we need to move on
|
||||
// to other strageties
|
||||
}
|
||||
}
|
||||
|
||||
// 2) look for the assembly in the "Bin" directory
|
||||
{
|
||||
string modulePath = HostingEnvironment.MapPath(descriptor.Location);
|
||||
modulePath = Path.Combine(modulePath, descriptor.Name);
|
||||
string moduleBinary = Path.Combine(modulePath, "bin");
|
||||
moduleBinary = Path.Combine(moduleBinary, descriptor.Name + ".dll");
|
||||
if (File.Exists(moduleBinary)) {
|
||||
// Copy file to dependencies directory
|
||||
string dependenciesPath = HostingEnvironment.MapPath("~/App_Data/Dependencies");
|
||||
if (!Directory.Exists(dependenciesPath)) {
|
||||
Directory.CreateDirectory(dependenciesPath);
|
||||
}
|
||||
string destFile = Path.Combine(dependenciesPath, descriptor.Name + ".dll");
|
||||
File.Copy(moduleBinary, destFile, true);
|
||||
var assembly = _buildManager.GetCompiledAssembly(projectPath);
|
||||
|
||||
// then load the assembly
|
||||
Assembly assembly = Assembly.Load(descriptor.Name);
|
||||
return CreateExtensionEntry(descriptor, assembly);
|
||||
}
|
||||
if (_hostEnvironment.IsFullTrust) {
|
||||
_dependenciesFolder.StoreAssemblyFile(descriptor.Name, assembly.Location);
|
||||
}
|
||||
|
||||
// 3) look for the csproj in the module directory
|
||||
{
|
||||
string projfileName = Path.Combine(descriptor.Location, descriptor.Name);
|
||||
projfileName = Path.Combine(projfileName, descriptor.Name + ".csproj").Replace('\\', '/');
|
||||
var assembly = BuildManager.GetCompiledAssembly(projfileName);
|
||||
return CreateExtensionEntry(descriptor, assembly);
|
||||
}
|
||||
}
|
||||
|
||||
private static ExtensionEntry CreateExtensionEntry(ExtensionDescriptor descriptor, Assembly assembly) {
|
||||
return new ExtensionEntry {
|
||||
Descriptor = descriptor,
|
||||
Assembly = assembly,
|
||||
|
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Compilation;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
public interface IBuildManager {
|
||||
IEnumerable<string> GetReferencedAssemblies();
|
||||
}
|
||||
|
||||
public class AspNetBuildManager : IBuildManager {
|
||||
public IEnumerable<string> GetReferencedAssemblies() {
|
||||
return BuildManager.GetReferencedAssemblies().Cast<string>();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Web.Hosting;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
public interface IVirtualPathProvider {
|
||||
string GetDirectoryName(string virtualPath);
|
||||
string Combine(params string[] paths);
|
||||
Stream OpenFile(string virtualPath);
|
||||
string MapPath(string virtualPath);
|
||||
}
|
||||
|
||||
public class AspNetVirtualPathProvider : IVirtualPathProvider {
|
||||
public string GetDirectoryName(string virtualPath) {
|
||||
return Path.GetDirectoryName(virtualPath);
|
||||
}
|
||||
|
||||
public string Combine(params string[] paths) {
|
||||
return Path.Combine(paths).Replace('\\', '/');
|
||||
}
|
||||
|
||||
public Stream OpenFile(string virtualPath) {
|
||||
return VirtualPathProvider.OpenFile(virtualPath);
|
||||
}
|
||||
|
||||
public string MapPath(string virtualPath) {
|
||||
return HostingEnvironment.MapPath(virtualPath);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +1,39 @@
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
/// Load an extension by looking into the "bin" subdirectory of an
|
||||
/// extension directory.
|
||||
/// </summary>
|
||||
public class PrecompiledExtensionLoader : IExtensionLoader {
|
||||
public int Order { get { return 3; } }
|
||||
private readonly IDependenciesFolder _folder;
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
|
||||
public PrecompiledExtensionLoader(IDependenciesFolder folder, IVirtualPathProvider virtualPathProvider) {
|
||||
_folder = folder;
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
}
|
||||
|
||||
public int Order { get { return 40; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
//var assembly = Assembly.Load(descriptor.Name);
|
||||
//return new ModuleEntry {
|
||||
// Descriptor = descriptor,
|
||||
// Assembly = assembly,
|
||||
// ExportedTypes = assembly.GetExportedTypes()
|
||||
//};
|
||||
var extensionPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Name, "bin",
|
||||
descriptor.Name + ".dll");
|
||||
if (!_virtualPathProvider.FileExists(extensionPath))
|
||||
return null;
|
||||
|
||||
_folder.StoreAssemblyFile(descriptor.Name, _virtualPathProvider.MapPath(extensionPath));
|
||||
|
||||
var assembly = _folder.LoadAssembly(descriptor.Name);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
return new ExtensionEntry {
|
||||
Descriptor = descriptor,
|
||||
Assembly = assembly,
|
||||
ExportedTypes = assembly.GetExportedTypes()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
/// Load an extension using the "Assembly.Load" method if the
|
||||
/// file can be found in the "App_Data/Dependencies" folder.
|
||||
/// </summary>
|
||||
public class ProbingExtensionLoader : IExtensionLoader {
|
||||
private readonly IDependenciesFolder _folder;
|
||||
|
||||
public ProbingExtensionLoader(IDependenciesFolder folder) {
|
||||
_folder = folder;
|
||||
}
|
||||
|
||||
public int Order { get { return 30; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
var assembly = _folder.LoadAssembly(descriptor.Name);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
return new ExtensionEntry {
|
||||
Descriptor = descriptor,
|
||||
Assembly = assembly,
|
||||
ExportedTypes = assembly.GetExportedTypes()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,8 +5,11 @@ using System.Web.Hosting;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
/// Load an extension by looking through the BuildManager referenced assemblies
|
||||
/// </summary>
|
||||
public class ReferencedExtensionLoader : IExtensionLoader {
|
||||
public int Order { get { return 2; } }
|
||||
public int Order { get { return 20; } }
|
||||
|
||||
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||
if (HostingEnvironment.IsHosted == false)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using System.CodeDom;
|
||||
using System.Web.Compilation;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
namespace Orchard.Environment {
|
||||
public interface IAssemblyBuilder {
|
||||
void AddCodeCompileUnit(CodeCompileUnit compileUnit);
|
||||
}
|
21
src/Orchard/Environment/IBuildManager.cs
Normal file
21
src/Orchard/Environment/IBuildManager.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Web.Compilation;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IBuildManager : IDependency {
|
||||
IEnumerable<Assembly> GetReferencedAssemblies();
|
||||
Assembly GetCompiledAssembly(string virtualPath);
|
||||
}
|
||||
|
||||
public class DefaultBuildManager : IBuildManager {
|
||||
public IEnumerable<Assembly> GetReferencedAssemblies() {
|
||||
return BuildManager.GetReferencedAssemblies().OfType<Assembly>();
|
||||
}
|
||||
|
||||
public Assembly GetCompiledAssembly(string virtualPath) {
|
||||
return BuildManager.GetCompiledAssembly(virtualPath);
|
||||
}
|
||||
}
|
||||
}
|
22
src/Orchard/Environment/IHostEnvironment.cs
Normal file
22
src/Orchard/Environment/IHostEnvironment.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Web.Hosting;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
/// <summary>
|
||||
/// Abstraction of the running environment
|
||||
/// </summary>
|
||||
public interface IHostEnvironment : IDependency {
|
||||
bool IsFullTrust { get; }
|
||||
string MapPath(string virtualPath);
|
||||
}
|
||||
|
||||
public class DefaultHostEnvironment : IHostEnvironment {
|
||||
public bool IsFullTrust {
|
||||
get { return AppDomain.CurrentDomain.IsFullyTrusted; }
|
||||
}
|
||||
|
||||
public string MapPath(string virtualPath) {
|
||||
return HostingEnvironment.MapPath(virtualPath);
|
||||
}
|
||||
}
|
||||
}
|
50
src/Orchard/Environment/IVirtualPathProvider.cs
Normal file
50
src/Orchard/Environment/IVirtualPathProvider.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
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);
|
||||
}
|
||||
|
||||
public class DefaultVirtualPathProvider : IVirtualPathProvider {
|
||||
public string GetDirectoryName(string virtualPath) {
|
||||
return Path.GetDirectoryName(virtualPath).Replace('\\', '/');
|
||||
}
|
||||
|
||||
public string Combine(params string[] paths) {
|
||||
return Path.Combine(paths).Replace('\\', '/');
|
||||
}
|
||||
|
||||
public Stream OpenFile(string virtualPath) {
|
||||
return HostingEnvironment.VirtualPathProvider.GetFile(virtualPath).Open();
|
||||
}
|
||||
|
||||
public StreamWriter CreateText(string virtualPath) {
|
||||
return File.CreateText(MapPath(virtualPath));
|
||||
}
|
||||
|
||||
public string MapPath(string virtualPath) {
|
||||
return HostingEnvironment.MapPath(virtualPath);
|
||||
}
|
||||
|
||||
public bool FileExists(string virtualPath) {
|
||||
return HostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string virtualPath) {
|
||||
return HostingEnvironment.VirtualPathProvider.DirectoryExists(virtualPath);
|
||||
}
|
||||
|
||||
public void CreateDirectory(string virtualPath) {
|
||||
Directory.CreateDirectory(MapPath(virtualPath));
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,6 +15,7 @@ using Orchard.Environment.State;
|
||||
using Orchard.Environment.Topology;
|
||||
using Orchard.Events;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Services;
|
||||
@@ -30,10 +31,14 @@ namespace Orchard.Environment {
|
||||
// a single default host implementation is needed for bootstrapping a web app domain
|
||||
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();
|
||||
|
||||
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
|
||||
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
|
||||
RegisterVolatileProvider<Clock, IClock>(builder);
|
||||
RegisterVolatileProvider<DefaultDependenciesFolder, IDependenciesFolder>(builder);
|
||||
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);
|
||||
|
||||
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().As<IEventHandler>().SingleInstance();
|
||||
{
|
||||
@@ -63,6 +68,7 @@ namespace Orchard.Environment {
|
||||
builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<ProbingExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
}
|
||||
}
|
||||
|
110
src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs
Normal file
110
src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public interface IDependenciesFolder : IVolatileProvider {
|
||||
void StoreAssemblyFile(string assemblyName, string assemblyFileName);
|
||||
Assembly LoadAssembly(string assemblyName);
|
||||
}
|
||||
|
||||
public class DefaultDependenciesFolder : IDependenciesFolder {
|
||||
private const string _basePath = "~/App_Data/Dependencies";
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
|
||||
public DefaultDependenciesFolder(IVirtualPathProvider virtualPathProvider) {
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
}
|
||||
|
||||
private string BasePath {
|
||||
get {
|
||||
return _basePath;
|
||||
}
|
||||
}
|
||||
|
||||
private string PersistencePath {
|
||||
get {
|
||||
return _virtualPathProvider.Combine(BasePath, "dependencies.xml");
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreAssemblyFile(string assemblyName, string assemblyFileName) {
|
||||
StoreAssemblyFile(assemblyName, assemblyFileName, Path.GetFileName(assemblyFileName));
|
||||
}
|
||||
|
||||
private void StoreAssemblyFile(string assemblyName, string assemblyFileName, string destinationFileName) {
|
||||
_virtualPathProvider.CreateDirectory(BasePath);
|
||||
|
||||
var destinationPath = _virtualPathProvider.MapPath(_virtualPathProvider.Combine(BasePath, destinationFileName));
|
||||
File.Copy(assemblyFileName, destinationPath);
|
||||
|
||||
StoreDepencyInformation(assemblyName, destinationFileName);
|
||||
}
|
||||
|
||||
private void StoreDepencyInformation(string name, string fileName) {
|
||||
var dependencies = ReadDependencies().ToList();
|
||||
|
||||
var dependency = dependencies.SingleOrDefault(d => d.Name == name);
|
||||
if (dependency == null) {
|
||||
dependency = new DependencyDescritpor { Name = name, FileName = fileName };
|
||||
dependencies.Add(dependency);
|
||||
}
|
||||
dependency.FileName = fileName;
|
||||
|
||||
WriteDependencies(dependencies);
|
||||
}
|
||||
|
||||
public Assembly LoadAssembly(string assemblyName) {
|
||||
_virtualPathProvider.CreateDirectory(BasePath);
|
||||
|
||||
var dependency = ReadDependencies().SingleOrDefault(d => d.Name == assemblyName);
|
||||
if (dependency == null)
|
||||
return null;
|
||||
|
||||
if (!_virtualPathProvider.FileExists(_virtualPathProvider.Combine(BasePath, dependency.FileName)))
|
||||
return null;
|
||||
|
||||
return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName));
|
||||
}
|
||||
|
||||
private class DependencyDescritpor {
|
||||
public string Name { get; set; }
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
|
||||
private IEnumerable<DependencyDescritpor> ReadDependencies() {
|
||||
if (!_virtualPathProvider.FileExists(PersistencePath))
|
||||
return Enumerable.Empty<DependencyDescritpor>();
|
||||
|
||||
using (var stream = _virtualPathProvider.OpenFile(PersistencePath)) {
|
||||
XDocument document = XDocument.Load(stream);
|
||||
return document
|
||||
.Elements(ns("Dependencies"))
|
||||
.Elements(ns("Dependency"))
|
||||
.Select(e => new DependencyDescritpor { Name = e.Element("Name").Value, FileName = e.Element("FileName").Value })
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteDependencies(IEnumerable<DependencyDescritpor> dependencies) {
|
||||
var document = new XDocument();
|
||||
document.Add(new XElement(ns("Dependencies")));
|
||||
var elements = dependencies.Select(d => new XElement("Dependency",
|
||||
new XElement(ns("Name"), d.Name),
|
||||
new XElement(ns("FileName"), d.FileName)));
|
||||
document.Root.Add(elements);
|
||||
|
||||
using (var stream = _virtualPathProvider.CreateText(PersistencePath)) {
|
||||
document.Save(stream, SaveOptions.None);
|
||||
}
|
||||
}
|
||||
|
||||
private static XName ns(string name) {
|
||||
return XName.Get(name/*, "http://schemas.microsoft.com/developer/msbuild/2003"*/);
|
||||
}
|
||||
}
|
||||
}
|
@@ -136,14 +136,17 @@
|
||||
<Compile Include="Data\DataModule.cs" />
|
||||
<Compile Include="Data\Orderable.cs" />
|
||||
<Compile Include="Environment\DefaultOrchardShell.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\CSharpExtensionBuildProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\CSharpExtensionCompiler.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\CSharpProjectExtensionCompilerMediumTrust.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\CSharpProjectFullTrustCompiler.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\CSharpProjectParser.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\IAssemblyBuilder.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\IBuildManager.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\IVirtualPathProvider.cs" />
|
||||
<Compile Include="Environment\IHostEnvironment.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\IDependenciesFolder.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpExtensionBuildProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpExtensionCompiler.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpProjectMediumTrustCompiler.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpProjectFullTrustCompiler.cs" />
|
||||
<Compile Include="Environment\Extensions\Compilers\CSharpProjectParser.cs" />
|
||||
<Compile Include="Environment\IAssemblyBuilder.cs" />
|
||||
<Compile Include="Environment\IBuildManager.cs" />
|
||||
<Compile Include="Environment\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