mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-14 10:54:50 +08:00
Perf: Don't call "GetReferencedAssemblies" when loading extensions
GetReferencedAssemblies forces all assemblies to be loaded, which has an impact on startup time. Since we know the name of the assemblies we need to load for extensions/modules, do a assembly name check instead. Also refactor code paths to always use the IBuildManager abstraction. --HG-- branch : dev
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.CodeDom.Compiler;
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -11,6 +12,12 @@ namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// Note: Currently not used...
|
||||
/// </summary>
|
||||
public class CSharpExtensionDirectoryCompiler {
|
||||
private readonly IBuildManager _buildManager;
|
||||
|
||||
public CSharpExtensionDirectoryCompiler(IBuildManager buildManager) {
|
||||
_buildManager = buildManager;
|
||||
}
|
||||
|
||||
public CompilerResults CompileProject(string location) {
|
||||
var codeProvider = CodeDomProvider.CreateProvider("cs");
|
||||
|
||||
@@ -23,10 +30,11 @@ namespace Orchard.Environment.Extensions.Compilers {
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAssemblyReferenceNames() {
|
||||
return Enumerable.Distinct<string>(BuildManager.GetReferencedAssemblies()
|
||||
.OfType<Assembly>()
|
||||
.Select(x => x.Location)
|
||||
.Where(x => !string.IsNullOrEmpty(x)));
|
||||
return _buildManager
|
||||
.GetReferencedAssemblies()
|
||||
.Select(x => x.Location)
|
||||
.Where(x => !string.IsNullOrEmpty(x))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetSourceFileNames(string path) {
|
||||
|
@@ -96,7 +96,7 @@ namespace Orchard.Environment.Extensions {
|
||||
foreach (var probe in extensionProbes) {
|
||||
Logger.Debug(" Loader: {0}", probe.Loader.Name);
|
||||
Logger.Debug(" VirtualPath: {0}", probe.VirtualPath);
|
||||
Logger.Debug(" DateTimeUtc: {0}", probe.LastModificationTimeUtc);
|
||||
Logger.Debug(" DateTimeUtc: {0}", probe.LastWriteTimeUtc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Orchard.Environment.Extensions {
|
||||
.Where(probe => probe != null))
|
||||
.GroupBy(e => e.Descriptor.Name)
|
||||
.ToDictionary(g => g.Key, g => g.AsEnumerable()
|
||||
.OrderByDescending(probe => probe.LastModificationTimeUtc)
|
||||
.OrderByDescending(probe => probe.LastWriteTimeUtc)
|
||||
.ThenBy(probe => probe.Loader.Order), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var deletedDependencies = previousDependencies
|
||||
@@ -222,57 +222,50 @@ namespace Orchard.Environment.Extensions {
|
||||
string referenceName,
|
||||
IList<DependencyReferenceDescriptor> activatedReferences) {
|
||||
|
||||
// Assemblies loaded by the BuildManager are ignored, since
|
||||
// we don't want to update them and they are automatically
|
||||
// referenced by the build manager
|
||||
if (_buildManager.GetReferencedAssemblies().Any(a => StringComparer.OrdinalIgnoreCase.Equals(a.GetName().Name, referenceName)))
|
||||
return;
|
||||
|
||||
// Binary references
|
||||
var references = context.ReferencesByName.ContainsKey(referenceName) ?
|
||||
context.ReferencesByName[referenceName] :
|
||||
Enumerable.Empty<ExtensionReferenceProbeEntry>();
|
||||
|
||||
// Binary references
|
||||
var bestBinaryReference = references
|
||||
.Where(entry => !string.IsNullOrEmpty(entry.VirtualPath))
|
||||
.Select(entry => new { Entry = entry, LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(entry.VirtualPath) })
|
||||
.OrderBy(e => e.LastWriteTimeUtc)
|
||||
.ThenBy(e => e.Entry.Name).FirstOrDefault();
|
||||
.ThenBy(e => e.Name).FirstOrDefault();
|
||||
|
||||
var bestProbe = context.ProcessedExtensions.ContainsKey(referenceName) ?
|
||||
var bestExtensionReference = context.ProcessedExtensions.ContainsKey(referenceName) ?
|
||||
context.ProcessedExtensions[referenceName] :
|
||||
null;
|
||||
|
||||
// Pick the best one of module vs binary
|
||||
if (bestProbe != null && bestBinaryReference != null) {
|
||||
if (bestProbe.LastModificationTimeUtc >= bestBinaryReference.LastWriteTimeUtc) {
|
||||
if (bestExtensionReference != null && bestBinaryReference != null) {
|
||||
if (bestExtensionReference.LastWriteTimeUtc >= bestBinaryReference.LastWriteTimeUtc) {
|
||||
bestBinaryReference = null;
|
||||
}
|
||||
else {
|
||||
bestProbe = null;
|
||||
bestExtensionReference = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Activate the binary ref
|
||||
if (bestBinaryReference != null) {
|
||||
if (!context.ProcessedReferences.Contains(bestBinaryReference.Entry.Name)) {
|
||||
context.ProcessedReferences.Add(bestBinaryReference.Entry.Name);
|
||||
bestBinaryReference.Entry.Loader.ReferenceActivated(context, bestBinaryReference.Entry);
|
||||
if (!context.ProcessedReferences.Contains(bestBinaryReference.Name)) {
|
||||
context.ProcessedReferences.Add(bestBinaryReference.Name);
|
||||
bestBinaryReference.Loader.ReferenceActivated(context, bestBinaryReference);
|
||||
}
|
||||
activatedReferences.Add(new DependencyReferenceDescriptor {
|
||||
LoaderName = bestBinaryReference.Entry.Loader.Name,
|
||||
Name = bestBinaryReference.Entry.Name,
|
||||
VirtualPath = bestBinaryReference.Entry.VirtualPath
|
||||
LoaderName = bestBinaryReference.Loader.Name,
|
||||
Name = bestBinaryReference.Name,
|
||||
VirtualPath = bestBinaryReference.VirtualPath
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Activated the module ref
|
||||
if (bestProbe != null) {
|
||||
if (bestExtensionReference != null) {
|
||||
activatedReferences.Add(new DependencyReferenceDescriptor {
|
||||
LoaderName = bestProbe.Loader.Name,
|
||||
LoaderName = bestExtensionReference.Loader.Name,
|
||||
Name = referenceName,
|
||||
VirtualPath = bestProbe.VirtualPath
|
||||
VirtualPath = bestExtensionReference.VirtualPath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
LastModificationTimeUtc = DateTime.MinValue,
|
||||
LastWriteTimeUtc = DateTime.MinValue,
|
||||
VirtualPath = "~/Areas/" + descriptor.Name,
|
||||
};
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
@@ -25,7 +25,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
if (descriptor.Location == "~/Core") {
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
LastModificationTimeUtc = DateTime.MinValue,
|
||||
LastWriteTimeUtc = DateTime.MinValue,
|
||||
Loader = this,
|
||||
VirtualPath = "~/Core/" + descriptor.Name
|
||||
};
|
||||
|
@@ -107,7 +107,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
LastModificationTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(projectPath),
|
||||
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(projectPath),
|
||||
Loader = this,
|
||||
VirtualPath = projectPath
|
||||
};
|
||||
|
@@ -10,7 +10,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
public ExtensionDescriptor Descriptor { get; set; }
|
||||
public IExtensionLoader Loader { get; set; }
|
||||
public string VirtualPath { get; set; }
|
||||
public DateTime LastModificationTimeUtc { get; set; }
|
||||
public DateTime LastWriteTimeUtc { get; set; }
|
||||
}
|
||||
|
||||
public class ExtensionReferenceProbeEntry {
|
||||
@@ -18,6 +18,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
public IExtensionLoader Loader { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string VirtualPath { get; set; }
|
||||
public DateTime LastWriteTimeUtc { get; set; }
|
||||
}
|
||||
|
||||
public interface IExtensionLoader {
|
||||
|
@@ -138,7 +138,8 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
Descriptor = descriptor,
|
||||
Loader = this,
|
||||
Name = Path.GetFileNameWithoutExtension(path),
|
||||
VirtualPath = path
|
||||
VirtualPath = path,
|
||||
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(path)
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -160,7 +161,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
LastModificationTimeUtc = File.GetLastWriteTimeUtc(_virtualPathProvider.MapPath(assemblyPath)),
|
||||
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(assemblyPath),
|
||||
Loader = this,
|
||||
VirtualPath = assemblyPath
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.FileSystems.Dependencies;
|
||||
@@ -86,7 +86,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
LastModificationTimeUtc = _assemblyProbingFolder.GetAssemblyDateTimeUtc(descriptor.Name),
|
||||
LastWriteTimeUtc = _assemblyProbingFolder.GetAssemblyDateTimeUtc(descriptor.Name),
|
||||
Loader = this,
|
||||
VirtualPath = desc.VirtualPath
|
||||
};
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Compilation;
|
||||
@@ -14,11 +15,13 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
/// </summary>
|
||||
public class ReferencedExtensionLoader : ExtensionLoaderBase {
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
private readonly IBuildManager _buildManager;
|
||||
|
||||
public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider)
|
||||
public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider, IBuildManager buildManager)
|
||||
: base(dependenciesFolder) {
|
||||
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
_buildManager = buildManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
@@ -49,16 +52,13 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
if (HostingEnvironment.IsHosted == false)
|
||||
return null;
|
||||
|
||||
var assembly = BuildManager.GetReferencedAssemblies()
|
||||
.OfType<Assembly>()
|
||||
.FirstOrDefault(x => x.GetName().Name == descriptor.Name);
|
||||
|
||||
var assembly = _buildManager.GetReferencedAssembly(descriptor.Name);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
return new ExtensionProbeEntry {
|
||||
Descriptor = descriptor,
|
||||
LastModificationTimeUtc = File.GetLastWriteTimeUtc(assembly.Location),
|
||||
LastWriteTimeUtc = File.GetLastWriteTimeUtc(assembly.Location),
|
||||
Loader = this,
|
||||
VirtualPath = _virtualPathProvider.Combine("~/bin", descriptor.Name + ".dll")
|
||||
};
|
||||
@@ -68,10 +68,7 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
if (HostingEnvironment.IsHosted == false)
|
||||
return null;
|
||||
|
||||
var assembly = BuildManager.GetReferencedAssemblies()
|
||||
.OfType<Assembly>()
|
||||
.FirstOrDefault(x => x.GetName().Name == descriptor.Name);
|
||||
|
||||
var assembly = _buildManager.GetReferencedAssembly(descriptor.Name);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
|
@@ -1,21 +1,54 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Web.Compilation;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IBuildManager : IDependency {
|
||||
IEnumerable<Assembly> GetReferencedAssemblies();
|
||||
Assembly GetReferencedAssembly(string name);
|
||||
Assembly GetCompiledAssembly(string virtualPath);
|
||||
}
|
||||
|
||||
public class DefaultBuildManager : IBuildManager {
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
|
||||
public DefaultBuildManager(IVirtualPathProvider virtualPathProvider) {
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
}
|
||||
|
||||
public IEnumerable<Assembly> GetReferencedAssemblies() {
|
||||
return BuildManager.GetReferencedAssemblies().OfType<Assembly>();
|
||||
}
|
||||
|
||||
public Assembly GetReferencedAssembly(string name) {
|
||||
var assemblyPath = _virtualPathProvider.Combine("~/bin", name + ".dll");
|
||||
if (!_virtualPathProvider.FileExists(assemblyPath))
|
||||
return null;
|
||||
|
||||
return Assembly.Load(name);
|
||||
}
|
||||
|
||||
|
||||
public Assembly GetCompiledAssembly(string virtualPath) {
|
||||
return BuildManager.GetCompiledAssembly(virtualPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildManagerExtensions {
|
||||
public static IEnumerable<string> GetReferencedAssemblyNames(this IBuildManager buildManager) {
|
||||
return buildManager
|
||||
.GetReferencedAssemblies()
|
||||
.Select(a => ExtractAssemblyName(a.FullName));
|
||||
}
|
||||
|
||||
public static string ExtractAssemblyName(string fullName) {
|
||||
int index = fullName.IndexOf(',');
|
||||
if (index < 0)
|
||||
return fullName;
|
||||
return fullName.Substring(0, index);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user