From fce27fd42d91f46458e9e28fb995cd1b70826193 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 9 Mar 2020 14:15:02 +1100 Subject: [PATCH] Ensures all assemblies at the same location as the entry point assemblies are queried. --- .../Composing/ReferenceResolver.cs | 67 +++++++++++++++++-- src/Umbraco.Core/Composing/TypeFinder.cs | 6 +- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Composing/ReferenceResolver.cs b/src/Umbraco.Core/Composing/ReferenceResolver.cs index 6d77afd414..c705af685a 100644 --- a/src/Umbraco.Core/Composing/ReferenceResolver.cs +++ b/src/Umbraco.Core/Composing/ReferenceResolver.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Reflection; @@ -15,27 +16,63 @@ namespace Umbraco.Core.Composing internal class ReferenceResolver { private readonly HashSet _umbracoAssemblies; - private readonly IReadOnlyList _assemblyItems; + private readonly IReadOnlyList _assemblies; private readonly Dictionary _classifications; private readonly List _lookup = new List(); - public ReferenceResolver(IReadOnlyList targetAssemblies, IReadOnlyList assemblyItems) + public ReferenceResolver(IReadOnlyList targetAssemblies, IReadOnlyList entryPointAssemblies) { _umbracoAssemblies = new HashSet(targetAssemblies, StringComparer.Ordinal); - _assemblyItems = assemblyItems; + _assemblies = entryPointAssemblies; _classifications = new Dictionary(); - foreach (var item in assemblyItems) + foreach (var item in entryPointAssemblies) { _lookup.Add(item); } } + /// + /// Returns a list of assemblies that directly reference or transitively reference the targetAssemblies + /// + /// + /// + /// This includes all assemblies in the same location as the entry point assemblies + /// public IEnumerable ResolveAssemblies() { var applicationParts = new List(); - foreach (var item in _assemblyItems) + var assemblies = new HashSet(_assemblies); + + // Get the unique directories of the assemblies + var assemblyLocations = GetAssemblyLocations(assemblies).ToList(); + + // Load in each assembly in the directory of the entry assembly to be included in the search + // for Umbraco dependencies/transitive dependencies + foreach(var location in assemblyLocations) + { + var dir = Path.GetDirectoryName(location); + + foreach(var dll in Directory.EnumerateFiles(dir, "*.dll")) + { + var assemblyName = AssemblyName.GetAssemblyName(dll); + + // don't include if this is excluded + if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assemblyName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase))) + continue; + + // don't include this item if it's Umbraco + // TODO: We should maybe pass an explicit list of these names in? + if (assemblyName.FullName.StartsWith("Umbraco.")) + continue; + + var assembly = Assembly.Load(assemblyName); + assemblies.Add(assembly); + } + } + + foreach (var item in assemblies) { var classification = Resolve(item); if (classification == Classification.ReferencesUmbraco || classification == Classification.IsUmbraco) @@ -47,6 +84,24 @@ namespace Umbraco.Core.Composing return applicationParts; } + + private IEnumerable GetAssemblyLocations(IEnumerable assemblies) + { + return assemblies.Select(x => GetAssemblyLocation(x).ToLowerInvariant()).Distinct(); + } + + // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs + private string GetAssemblyLocation(Assembly assembly) + { + if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out var result) && + result.IsFile && string.IsNullOrWhiteSpace(result.Fragment)) + { + return result.LocalPath; + } + + return assembly.Location; + } + private Classification Resolve(Assembly assemblyItem) { if (_classifications.TryGetValue(assemblyItem, out var classification)) @@ -88,7 +143,7 @@ namespace Umbraco.Core.Composing foreach (var referenceName in assembly.GetReferencedAssemblies()) { // don't include if this is excluded - if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => referenceName.FullName.StartsWith(f))) + if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => referenceName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase))) continue; var reference = Assembly.Load(referenceName); diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs index bc15cb63f2..1813c8d8f4 100644 --- a/src/Umbraco.Core/Composing/TypeFinder.cs +++ b/src/Umbraco.Core/Composing/TypeFinder.cs @@ -142,8 +142,12 @@ namespace Umbraco.Core.Composing "itextsharp,", "mscorlib,", "NUnit,", - "NUnit3TestAdapter,", + "NUnit.", + "NUnit3.", "Selenium.", + "ImageProcessor", + "MiniProfiler.", + "Owin,", }; ///