mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 11:44:58 +08:00
Adding new ProbingExtensionLoader, and fixing DynamicCompilation priority.
The DyanmicExtensionLoader could randomly take over PrecompiledExtensionLoader as the Priority was not set on ProbeExtensionEntry. Also a new ProbingExtensionLoader is added and is used when DyanmicExtensionLoader is disabled. It will compile an extension dynamically but cache the assembly in the probing folder (Dependencies) so that it's not recompiled on each app start, and such that there is no need to inspect dependency files. --HG-- branch : 1.x
This commit is contained in:
@@ -21,6 +21,10 @@
|
||||
</UpgradeBackupLocation>
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@@ -171,6 +171,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
var result = new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
Priority = 50,
|
||||
VirtualPath = projectPath,
|
||||
VirtualPathDependencies = GetDependencies(projectPath).ToList(),
|
||||
};
|
||||
|
@@ -173,7 +173,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
// A pre-compiled module is _not_ compatible with a dynamically loaded module
|
||||
// because a pre-compiled module usually references a pre-compiled assembly binary
|
||||
// which will have a different identity (i.e. name) from the dynamic module.
|
||||
bool result = references.All(r => r.Loader.GetType() != typeof (DynamicExtensionLoader));
|
||||
bool result = references.All(r => r.Loader.GetType() != typeof(DynamicExtensionLoader) && r.Loader.GetType() != typeof(ProbingExtensionLoader));
|
||||
if (!result) {
|
||||
Logger.Information("Extension \"{0}\" will not be loaded as pre-compiled extension because one or more referenced extension is dynamically compiled", extension.Id);
|
||||
}
|
||||
@@ -193,6 +193,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
var result = new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
Priority = 80,
|
||||
VirtualPath = assemblyPath,
|
||||
VirtualPathDependencies = new[] { assemblyPath },
|
||||
};
|
||||
|
@@ -0,0 +1,225 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment.Extensions.Compilers;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// <summary>
|
||||
/// In case <see cref="DynamicExtensionLoader"/> is disabled, this loader will dynamically compile the assembly
|
||||
/// and save a copy to the probing folder so that next restart doesn't need to compile it again.
|
||||
/// </summary>
|
||||
public class ProbingExtensionLoader : ExtensionLoaderBase {
|
||||
public static readonly string[] ExtensionsVirtualPathPrefixes = { "~/Modules/", "~/Themes/" };
|
||||
|
||||
private readonly IBuildManager _buildManager;
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private readonly IAssemblyProbingFolder _assemblyProbingFolder;
|
||||
private readonly IDependenciesFolder _dependenciesFolder;
|
||||
private readonly IProjectFileParser _projectFileParser;
|
||||
|
||||
public ProbingExtensionLoader(
|
||||
IBuildManager buildManager,
|
||||
IVirtualPathProvider virtualPathProvider,
|
||||
IVirtualPathMonitor virtualPathMonitor,
|
||||
IHostEnvironment hostEnvironment,
|
||||
IAssemblyProbingFolder assemblyProbingFolder,
|
||||
IDependenciesFolder dependenciesFolder,
|
||||
IProjectFileParser projectFileParser)
|
||||
: base(dependenciesFolder) {
|
||||
|
||||
_buildManager = buildManager;
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_assemblyProbingFolder = assemblyProbingFolder;
|
||||
_projectFileParser = projectFileParser;
|
||||
_dependenciesFolder = dependenciesFolder;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
public override int Order { get { return 110; } }
|
||||
|
||||
public override IEnumerable<ExtensionCompilationReference> GetCompilationReferences(DependencyDescriptor dependency) {
|
||||
yield return new ExtensionCompilationReference { BuildProviderTarget = dependency.VirtualPath };
|
||||
}
|
||||
|
||||
public override void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) {
|
||||
}
|
||||
|
||||
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
|
||||
}
|
||||
|
||||
public override void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptor descriptor) {
|
||||
if (Disabled)
|
||||
return Enumerable.Empty<ExtensionReferenceProbeEntry>();
|
||||
|
||||
Logger.Information("Probing references for module '{0}'", descriptor.Id);
|
||||
|
||||
string projectPath = GetProjectPath(descriptor);
|
||||
if (projectPath == null)
|
||||
return Enumerable.Empty<ExtensionReferenceProbeEntry>();
|
||||
|
||||
var projectFile = _projectFileParser.Parse(projectPath);
|
||||
|
||||
var result = projectFile.References.Select(r => new ExtensionReferenceProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
Name = r.SimpleName,
|
||||
VirtualPath = _virtualPathProvider.GetProjectReferenceVirtualPath(projectPath, r.SimpleName, r.Path)
|
||||
});
|
||||
|
||||
Logger.Information("Done probing references for module '{0}'", descriptor.Id);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Assembly LoadReference(DependencyReferenceDescriptor reference) {
|
||||
if (Disabled)
|
||||
return null;
|
||||
|
||||
Logger.Information("Loading reference '{0}'", reference.Name);
|
||||
|
||||
// DynamicExtensionLoader has 2 types of references: assemblies from module bin directory
|
||||
// and .csproj.
|
||||
Assembly result;
|
||||
if (StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(reference.VirtualPath), ".dll"))
|
||||
result = _assemblyProbingFolder.LoadAssembly(reference.Name);
|
||||
else {
|
||||
result = ProbeAssembly(reference.Name, reference.VirtualPath);
|
||||
}
|
||||
|
||||
Logger.Information("Done loading reference '{0}'", reference.Name);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) {
|
||||
if (Disabled)
|
||||
return null;
|
||||
|
||||
Logger.Information("Probing for module '{0}'", descriptor.Id);
|
||||
|
||||
string projectPath = GetProjectPath(descriptor);
|
||||
if (projectPath == null)
|
||||
return null;
|
||||
|
||||
var result = new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
Priority = 50,
|
||||
VirtualPath = projectPath,
|
||||
VirtualPathDependencies = new string[] { projectPath },
|
||||
};
|
||||
|
||||
Logger.Information("Done probing for module '{0}'", descriptor.Id);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) {
|
||||
if (Disabled)
|
||||
return null;
|
||||
|
||||
Logger.Information("Start loading dynamic extension \"{0}\"", descriptor.Name);
|
||||
|
||||
var assembly = _assemblyProbingFolder.LoadAssembly(descriptor.Id);
|
||||
if (assembly == null) {
|
||||
string projectPath = GetProjectPath(descriptor);
|
||||
if (projectPath == null)
|
||||
return null;
|
||||
|
||||
assembly = ProbeAssembly(descriptor.Id, projectPath);
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
Logger.Information("Done loading dynamic extension \"{0}\": assembly name=\"{1}\"", descriptor.Name, assembly.FullName);
|
||||
|
||||
return new ExtensionEntry {
|
||||
Descriptor = descriptor,
|
||||
Assembly = assembly,
|
||||
ExportedTypes = assembly.GetExportedTypes(),
|
||||
};
|
||||
}
|
||||
|
||||
private void AddDependencies(string projectPath, HashSet<string> currentSet) {
|
||||
// Skip files from locations other than "~/Modules" and "~/Themes"
|
||||
if (string.IsNullOrEmpty(PrefixMatch(projectPath, ExtensionsVirtualPathPrefixes))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add project path
|
||||
currentSet.Add(projectPath);
|
||||
|
||||
// Add source file paths
|
||||
var projectFile = _projectFileParser.Parse(projectPath);
|
||||
string basePath = _virtualPathProvider.GetDirectoryName(projectPath);
|
||||
currentSet.UnionWith(projectFile.SourceFilenames.Select(f => _virtualPathProvider.Combine(basePath, f)));
|
||||
|
||||
// Add Project and Library references
|
||||
if (projectFile.References != null) {
|
||||
foreach (ReferenceDescriptor referenceDescriptor in projectFile.References.Where(reference => !string.IsNullOrEmpty(reference.Path))) {
|
||||
string path = referenceDescriptor.ReferenceType == ReferenceType.Library
|
||||
? _virtualPathProvider.GetProjectReferenceVirtualPath(projectPath, referenceDescriptor.SimpleName, referenceDescriptor.Path)
|
||||
: _virtualPathProvider.Combine(basePath, referenceDescriptor.Path);
|
||||
|
||||
// Normalize the virtual path (avoid ".." in the path name)
|
||||
if (!string.IsNullOrEmpty(path)) {
|
||||
path = _virtualPathProvider.ToAppRelative(path);
|
||||
}
|
||||
|
||||
// Attempt to reference the project / library file
|
||||
if (!string.IsNullOrEmpty(path) && !currentSet.Contains(path) && _virtualPathProvider.TryFileExists(path)) {
|
||||
switch (referenceDescriptor.ReferenceType) {
|
||||
case ReferenceType.Project:
|
||||
AddDependencies(path, currentSet);
|
||||
break;
|
||||
case ReferenceType.Library:
|
||||
currentSet.Add(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Assembly ProbeAssembly(string moduleName, string virtualPath) {
|
||||
var assembly = _buildManager.GetCompiledAssembly(virtualPath);
|
||||
if (assembly != null) {
|
||||
_assemblyProbingFolder.StoreAssembly(moduleName, assembly.Location);
|
||||
return assembly;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string PrefixMatch(string virtualPath, params string[] prefixes) {
|
||||
return prefixes
|
||||
.FirstOrDefault(p => virtualPath.StartsWith(p, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private string GetProjectPath(ExtensionDescriptor descriptor) {
|
||||
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
|
||||
descriptor.Id + ".csproj");
|
||||
|
||||
if (!_virtualPathProvider.FileExists(projectPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return projectPath;
|
||||
}
|
||||
}
|
||||
}
|
@@ -103,6 +103,7 @@ namespace Orchard.Environment {
|
||||
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<ProbingExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
builder.RegisterType<RawThemeExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||
}
|
||||
}
|
||||
|
@@ -111,6 +111,7 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
// implementations.
|
||||
return
|
||||
loaderName == "DynamicExtensionLoader" ||
|
||||
loaderName == "ProbingExtensionLoader" ||
|
||||
loaderName == "PrecompiledExtensionLoader";
|
||||
}
|
||||
|
||||
|
@@ -201,6 +201,7 @@
|
||||
<Compile Include="Environment\Extensions\Folders\CoreModuleFolders.cs" />
|
||||
<Compile Include="Environment\Extensions\Folders\IExtensionHarvester.cs" />
|
||||
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
|
||||
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
|
||||
<Compile Include="Environment\Features\IFeatureManager.cs" />
|
||||
<Compile Include="Environment\IAssemblyNameResolver.cs" />
|
||||
|
Reference in New Issue
Block a user