diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
new file mode 100644
index 0000000000..61d7cff240
--- /dev/null
+++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Returns a list of scannable assemblies based on an entry point assembly and it's references
+ ///
+ ///
+ /// This will recursively search through the entry point's assemblies and Umbraco's core assemblies and their references
+ /// to create a list of scannable assemblies based on whether they themselves or their transitive dependencies reference Umbraco core assemblies.
+ ///
+ public class DefaultUmbracoAssemblyProvider : IAssemblyProvider
+ {
+ private readonly Assembly _entryPointAssembly;
+ private static readonly string[] UmbracoCoreAssemblyNames = new[]
+ {
+ "Umbraco.Core",
+ "Umbraco.Web",
+ "Umbraco.Infrastructure",
+ "Umbraco.PublishedCache.NuCache",
+ "Umbraco.ModelsBuilder.Embedded",
+ "Umbraco.Examine.Lucene",
+ };
+
+ public DefaultUmbracoAssemblyProvider(Assembly entryPointAssembly)
+ {
+ _entryPointAssembly = entryPointAssembly ?? throw new ArgumentNullException(nameof(entryPointAssembly));
+ }
+
+ // TODO: It would be worth investigating a netcore3 version of this which would use
+ // var allAssemblies = System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies);
+ // that will still only resolve Assemblies that are already loaded but it would also make it possible to
+ // query dynamically generated assemblies once they are added. It would also provide the ability to probe
+ // assembly locations that are not in the same place as the entry point assemblies.
+
+ public IEnumerable Assemblies
+ {
+ get
+ {
+ var finder = new FindAssembliesWithReferencesTo(new[] { _entryPointAssembly }, UmbracoCoreAssemblyNames, true);
+ return finder.Find();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
new file mode 100644
index 0000000000..91225ff973
--- /dev/null
+++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Finds Assemblies from the entry point assemblies, it's dependencies and it's transitive dependencies that reference that targetAssemblyNames
+ ///
+ ///
+ /// borrowed and modified from here https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/FindAssembliesWithReferencesTo.cs
+ ///
+ internal class FindAssembliesWithReferencesTo
+ {
+ private readonly Assembly[] _referenceAssemblies;
+ private readonly string[] _targetAssemblies;
+ private readonly bool _includeTargets;
+
+ ///
+ /// Constructor
+ ///
+ /// Entry point assemblies
+ /// Used to check if the entry point or it's transitive assemblies reference these assembly names
+ /// If true will also use the target assembly names as entry point assemblies
+ public FindAssembliesWithReferencesTo(Assembly[] referenceAssemblies, string[] targetAssemblyNames, bool includeTargets)
+ {
+ _referenceAssemblies = referenceAssemblies;
+ _targetAssemblies = targetAssemblyNames;
+ _includeTargets = includeTargets;
+ }
+
+ public IEnumerable Find()
+ {
+ var referenceItems = new List();
+ foreach (var assembly in _referenceAssemblies)
+ {
+ referenceItems.Add(assembly);
+ }
+
+ if (_includeTargets)
+ {
+ foreach(var target in _targetAssemblies)
+ {
+ referenceItems.Add(Assembly.Load(target));
+ }
+ }
+
+ var provider = new ReferenceResolver(_targetAssemblies, referenceItems);
+ var assemblyNames = provider.ResolveAssemblies();
+ return assemblyNames.ToList();
+ }
+
+ }
+}
diff --git a/src/Umbraco.Core/Composing/IAssemblyProvider.cs b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
new file mode 100644
index 0000000000..bde97a9556
--- /dev/null
+++ b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Provides a list of assemblies that can be scanned
+ ///
+ public interface IAssemblyProvider
+ {
+ IEnumerable Assemblies { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/ReferenceResolver.cs b/src/Umbraco.Core/Composing/ReferenceResolver.cs
new file mode 100644
index 0000000000..65dba8bf23
--- /dev/null
+++ b/src/Umbraco.Core/Composing/ReferenceResolver.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Resolves assemblies that reference one of the specified "targetAssemblies" either directly or transitively.
+ ///
+ ///
+ /// Borrowed and modified from https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/ReferenceResolver.cs
+ ///
+ internal class ReferenceResolver
+ {
+ private readonly HashSet _umbracoAssemblies;
+ private readonly IReadOnlyList _assemblies;
+ private readonly Dictionary _classifications;
+ private readonly List _lookup = new List();
+
+ public ReferenceResolver(IReadOnlyList targetAssemblies, IReadOnlyList entryPointAssemblies)
+ {
+ _umbracoAssemblies = new HashSet(targetAssemblies, StringComparer.Ordinal);
+ _assemblies = entryPointAssemblies;
+ _classifications = new Dictionary();
+
+ 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();
+
+ var assemblies = new HashSet(_assemblies);
+
+ // Get the unique directories of the assemblies
+ var assemblyLocations = GetAssemblyFolders(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 dir in assemblyLocations)
+ {
+ 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)
+ {
+ applicationParts.Add(item);
+ }
+ }
+
+ return applicationParts;
+ }
+
+
+ private IEnumerable GetAssemblyFolders(IEnumerable assemblies)
+ {
+ return assemblies.Select(x => Path.GetDirectoryName(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 assembly)
+ {
+ if (_classifications.TryGetValue(assembly, out var classification))
+ {
+ return classification;
+ }
+
+ // Initialize the dictionary with a value to short-circuit recursive references.
+ classification = Classification.Unknown;
+ _classifications[assembly] = classification;
+
+ if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assembly.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
+ {
+ // if its part of the filter it doesn't reference umbraco
+ classification = Classification.DoesNotReferenceUmbraco;
+ }
+ else if (_umbracoAssemblies.Contains(assembly.GetName().Name))
+ {
+ classification = Classification.IsUmbraco;
+ }
+ else
+ {
+ classification = Classification.DoesNotReferenceUmbraco;
+ foreach (var reference in GetReferences(assembly))
+ {
+ // recurse
+ var referenceClassification = Resolve(reference);
+
+ if (referenceClassification == Classification.IsUmbraco || referenceClassification == Classification.ReferencesUmbraco)
+ {
+ classification = Classification.ReferencesUmbraco;
+ break;
+ }
+ }
+ }
+
+ Debug.Assert(classification != Classification.Unknown);
+ _classifications[assembly] = classification;
+ return classification;
+ }
+
+ protected virtual IEnumerable GetReferences(Assembly assembly)
+ {
+ foreach (var referenceName in assembly.GetReferencedAssemblies())
+ {
+ // don't include if this is excluded
+ if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => referenceName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
+ continue;
+
+ var reference = Assembly.Load(referenceName);
+
+ if (!_lookup.Contains(reference))
+ {
+ // A dependency references an item that isn't referenced by this project.
+ // We'll add this reference so that we can calculate the classification.
+
+ _lookup.Add(reference);
+ }
+ yield return reference;
+ }
+ }
+
+ protected enum Classification
+ {
+ Unknown,
+ DoesNotReferenceUmbraco,
+ ReferencesUmbraco,
+ IsUmbraco,
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs
index 9d88153b0a..79fddad1ca 100644
--- a/src/Umbraco.Core/Composing/TypeFinder.cs
+++ b/src/Umbraco.Core/Composing/TypeFinder.cs
@@ -1,106 +1,35 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Configuration;
-using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Text;
using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.Exceptions;
-using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Composing
{
+
///
public class TypeFinder : ITypeFinder
{
private readonly ILogger _logger;
-
- public TypeFinder(ILogger logger, ITypeFinderConfig typeFinderConfig = null)
- {
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty();
- _allAssemblies = new Lazy>(() =>
- {
- HashSet assemblies = null;
- try
- {
- //NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have
- // already been loaded in to the app domain, instead we will look directly into the bin folder and load each one.
- var binFolder = GetRootDirectorySafe();
- var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- //var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
- //var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- assemblies = new HashSet();
- foreach (var a in binAssemblyFiles)
- {
- try
- {
- var assName = AssemblyName.GetAssemblyName(a);
- var ass = Assembly.Load(assName);
- assemblies.Add(ass);
- }
- catch (Exception e)
- {
- if (e is SecurityException || e is BadImageFormatException)
- {
- //swallow these exceptions
- }
- else
- {
- throw;
- }
- }
- }
-
- //Since we are only loading in the /bin assemblies above, we will also load in anything that's already loaded (which will include gac items)
- foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
- {
- assemblies.Add(a);
- }
- }
- catch (InvalidOperationException e)
- {
- if (e.InnerException is SecurityException == false)
- throw;
- }
-
- return assemblies;
- });
- }
-
- //Lazy access to the all assemblies list
- private readonly Lazy> _allAssemblies;
+ private readonly IAssemblyProvider _assemblyProvider;
private volatile HashSet _localFilteredAssemblyCache;
private readonly object _localFilteredAssemblyCacheLocker = new object();
private readonly List _notifiedLoadExceptionAssemblies = new List();
- private static readonly ConcurrentDictionary TypeNamesCache= new ConcurrentDictionary();
- private string _rootDir = "";
+ private static readonly ConcurrentDictionary TypeNamesCache = new ConcurrentDictionary();
private readonly string[] _assembliesAcceptingLoadExceptions;
- // FIXME - this is only an interim change, once the IIOHelper stuff is merged we should use IIOHelper here
- private string GetRootDirectorySafe()
+ // used for benchmark tests
+ internal bool QueryWithReferencingAssemblies = true;
+
+ public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, ITypeFinderConfig typeFinderConfig = null)
{
- if (string.IsNullOrEmpty(_rootDir) == false)
- {
- return _rootDir;
- }
-
- var codeBase = Assembly.GetExecutingAssembly().CodeBase;
- var uri = new Uri(codeBase);
- var path = uri.LocalPath;
- var baseDirectory = Path.GetDirectoryName(path);
- if (string.IsNullOrEmpty(baseDirectory))
- throw new PanicException("No root directory could be resolved.");
-
- _rootDir = baseDirectory.Contains("bin")
- ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
- : baseDirectory;
-
- return _rootDir;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _assemblyProvider = assemblyProvider;
+ _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty();
}
private bool AcceptsLoadExceptions(Assembly a)
@@ -119,22 +48,8 @@ namespace Umbraco.Core.Composing
});
}
- ///
- /// lazily load a reference to all assemblies and only local assemblies.
- /// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
- ///
- ///
- /// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
- /// loaded in the CLR, not all assemblies.
- /// See these threads:
- /// http://issues.umbraco.org/issue/U5-198
- /// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
- /// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
- ///
- private IEnumerable GetAllAssemblies()
- {
- return _allAssemblies.Value;
- }
+
+ private IEnumerable GetAllAssemblies() => _assemblyProvider.Assemblies;
///
public IEnumerable AssembliesToScan
@@ -181,7 +96,10 @@ namespace Umbraco.Core.Composing
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
///
- private static readonly string[] KnownAssemblyExclusionFilter = {
+ internal static readonly string[] KnownAssemblyExclusionFilter = {
+ "mscorlib,",
+ "netstandard,",
+ "System,",
"Antlr3.",
"AutoMapper,",
"AutoMapper.",
@@ -228,7 +146,14 @@ namespace Umbraco.Core.Composing
"WebDriver,",
"itextsharp,",
"mscorlib,",
- "nunit.framework,",
+ "NUnit,",
+ "NUnit.",
+ "NUnit3.",
+ "Selenium.",
+ "ImageProcessor",
+ "MiniProfiler.",
+ "Owin,",
+ "SQLite",
};
///
@@ -290,6 +215,11 @@ namespace Umbraco.Core.Composing
///
public virtual Type GetTypeByName(string name)
{
+
+ //NOTE: This will not find types in dynamic assemblies unless those assemblies are already loaded
+ //into the appdomain.
+
+
// This is exactly what the BuildManager does, if the type is an assembly qualified type
// name it will find it.
if (TypeNameContainsAssembly(name))
@@ -340,18 +270,24 @@ namespace Umbraco.Core.Composing
var stack = new Stack();
stack.Push(attributeType.Assembly);
+ if (!QueryWithReferencingAssemblies)
+ {
+ foreach (var a in candidateAssemblies)
+ stack.Push(a);
+ }
+
while (stack.Count > 0)
{
var assembly = stack.Pop();
- Type[] assemblyTypes = null;
+ IReadOnlyList assemblyTypes = null;
if (assembly != attributeType.Assembly || attributeAssemblyIsCandidate)
{
// get all assembly types that can be assigned to baseType
try
{
assemblyTypes = GetTypesWithFormattedException(assembly)
- .ToArray(); // in try block
+ .ToList(); // in try block
}
catch (TypeLoadException ex)
{
@@ -371,10 +307,13 @@ namespace Umbraco.Core.Composing
if (assembly != attributeType.Assembly && assemblyTypes.Where(attributeType.IsAssignableFrom).Any() == false)
continue;
- foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ if (QueryWithReferencingAssemblies)
{
- candidateAssemblies.Remove(referencing);
- stack.Push(referencing);
+ foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ {
+ candidateAssemblies.Remove(referencing);
+ stack.Push(referencing);
+ }
}
}
@@ -405,19 +344,25 @@ namespace Umbraco.Core.Composing
var stack = new Stack();
stack.Push(baseType.Assembly);
+ if (!QueryWithReferencingAssemblies)
+ {
+ foreach (var a in candidateAssemblies)
+ stack.Push(a);
+ }
+
while (stack.Count > 0)
{
var assembly = stack.Pop();
// get all assembly types that can be assigned to baseType
- Type[] assemblyTypes = null;
+ IReadOnlyList assemblyTypes = null;
if (assembly != baseType.Assembly || baseTypeAssemblyIsCandidate)
{
try
{
assemblyTypes = GetTypesWithFormattedException(assembly)
.Where(baseType.IsAssignableFrom)
- .ToArray(); // in try block
+ .ToList(); // in try block
}
catch (TypeLoadException ex)
{
@@ -437,10 +382,13 @@ namespace Umbraco.Core.Composing
if (assembly != baseType.Assembly && assemblyTypes.All(x => x.IsSealed))
continue;
- foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ if (QueryWithReferencingAssemblies)
{
- candidateAssemblies.Remove(referencing);
- stack.Push(referencing);
+ foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ {
+ candidateAssemblies.Remove(referencing);
+ stack.Push(referencing);
+ }
}
}
@@ -522,6 +470,5 @@ namespace Umbraco.Core.Composing
#endregion
-
}
}
diff --git a/src/Umbraco.Core/Composing/TypeFinderConfig.cs b/src/Umbraco.Core/Composing/TypeFinderConfig.cs
new file mode 100644
index 0000000000..3dc672b27c
--- /dev/null
+++ b/src/Umbraco.Core/Composing/TypeFinderConfig.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// TypeFinder config via appSettings
+ ///
+ internal class TypeFinderConfig : ITypeFinderConfig
+ {
+ private readonly ITypeFinderSettings _settings;
+ private IEnumerable _assembliesAcceptingLoadExceptions;
+
+ public TypeFinderConfig(ITypeFinderSettings settings)
+ {
+ _settings = settings;
+ }
+
+ public IEnumerable AssembliesAcceptingLoadExceptions
+ {
+ get
+ {
+ if (_assembliesAcceptingLoadExceptions != null)
+ return _assembliesAcceptingLoadExceptions;
+
+ var s = _settings.AssembliesAcceptingLoadExceptions;
+ return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
+ ? Array.Empty()
+ : s.Split(',').Select(x => x.Trim()).ToArray();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeHelper.cs b/src/Umbraco.Core/Composing/TypeHelper.cs
index 28eab6a5ec..1987a4059c 100644
--- a/src/Umbraco.Core/Composing/TypeHelper.cs
+++ b/src/Umbraco.Core/Composing/TypeHelper.cs
@@ -82,9 +82,9 @@ namespace Umbraco.Core.Composing
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
/// reference that assembly, same with the global.asax assembly.
///
- public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies)
+ public static IReadOnlyList GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies)
{
- if (assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
+ if (assembly.IsDynamic || assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
return EmptyAssemblies;
@@ -92,7 +92,7 @@ namespace Umbraco.Core.Composing
// should only be scanning those assemblies because any other assembly will definitely not
// contain sub type's of the one we're currently looking for
var name = assembly.GetName().Name;
- return assemblies.Where(x => x == assembly || HasReference(x, name)).ToArray();
+ return assemblies.Where(x => x == assembly || HasReference(x, name)).ToList();
}
///
diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs
index 76d00c472d..4d8b5c984c 100644
--- a/src/Umbraco.Core/Composing/TypeLoader.cs
+++ b/src/Umbraco.Core/Composing/TypeLoader.cs
@@ -516,29 +516,29 @@ namespace Umbraco.Core.Composing
#region Get Assembly Attributes
- ///
- /// Gets the assembly attributes of the specified type .
- ///
- /// The attribute type.
- ///
- /// The assembly attributes of the specified type .
- ///
- public IEnumerable GetAssemblyAttributes()
- where T : Attribute
- {
- return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
- }
+ /////
+ ///// Gets the assembly attributes of the specified type .
+ /////
+ ///// The attribute type.
+ /////
+ ///// The assembly attributes of the specified type .
+ /////
+ //public IEnumerable GetAssemblyAttributes()
+ // where T : Attribute
+ //{
+ // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
+ //}
- ///
- /// Gets all the assembly attributes.
- ///
- ///
- /// All assembly attributes.
- ///
- public IEnumerable GetAssemblyAttributes()
- {
- return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
- }
+ /////
+ ///// Gets all the assembly attributes.
+ /////
+ /////
+ ///// All assembly attributes.
+ /////
+ //public IEnumerable GetAssemblyAttributes()
+ //{
+ // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
+ //}
///
/// Gets the assembly attributes of the specified .
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 38731ce21c..7b1aff1a4b 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Reflection;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
@@ -369,7 +370,21 @@ namespace Umbraco.Core.Runtime
///
///
protected virtual ITypeFinder GetTypeFinder()
- => new TypeFinder(Logger);
+ // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
+ // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
+ => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
+ // GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website
+ // in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since
+ // the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly()
+ // which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK.
+ // If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own
+ // code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting
+ // from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance
+ // of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point
+ // assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one.
+ // For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are
+ // getting rid of netframework.
+ Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()));
///
diff --git a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs
new file mode 100644
index 0000000000..7b4322bfac
--- /dev/null
+++ b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs
@@ -0,0 +1,30 @@
+using BenchmarkDotNet.Attributes;
+using System;
+using System.Linq;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+using Umbraco.Tests.Benchmarks.Config;
+
+namespace Umbraco.Tests.Benchmarks
+{
+ [MediumRunJob]
+ [MemoryDiagnoser]
+ public class TypeFinderBenchmarks
+ {
+
+ [Benchmark(Baseline = true)]
+ public void WithGetReferencingAssembliesCheck()
+ {
+ var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ var found = typeFinder1.FindClassesOfType().Count();
+ }
+
+ [Benchmark]
+ public void WithoutGetReferencingAssembliesCheck()
+ {
+ var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+ typeFinder2.QueryWithReferencingAssemblies = false;
+ var found = typeFinder2.FindClassesOfType().Count();
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
index 7566d8ab85..84ec535b9d 100644
--- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
+++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
@@ -61,6 +61,7 @@
+
diff --git a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs
index 3a504ad4e2..e4844cc6be 100644
--- a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs
+++ b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Tests.Collections;
+using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Cache;
namespace Umbraco.Tests.Cache
@@ -28,7 +29,7 @@ namespace Umbraco.Tests.Cache
public override void Setup()
{
base.Setup();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
_memberCache = new ObjectCacheAppCache(typeFinder);
_provider = new DeepCloneAppCache(_memberCache);
diff --git a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs
index b9c948c1de..dbda6fb429 100644
--- a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs
+++ b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs
@@ -16,7 +16,7 @@ namespace Umbraco.Tests.Cache
public override void Setup()
{
base.Setup();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
_ctx = new FakeHttpContextFactory("http://localhost/test");
_appCache = new HttpRequestAppCache(() => _ctx.HttpContext.Items, typeFinder);
}
diff --git a/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs
index 772e92cabe..7957026ad8 100644
--- a/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs
+++ b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs
@@ -1,10 +1,7 @@
-using System.Collections.Generic;
-using System.Linq;
-using Moq;
+using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Cache;
-using Umbraco.Core.Composing;
-using Umbraco.Core.Logging;
+using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Cache
{
@@ -21,7 +18,7 @@ namespace Umbraco.Tests.Cache
public override void Setup()
{
base.Setup();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
_provider = new ObjectCacheAppCache(typeFinder);
}
diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs
index bef72e5fb7..7dc6025b0a 100644
--- a/src/Umbraco.Tests/Components/ComponentTests.cs
+++ b/src/Umbraco.Tests/Components/ComponentTests.cs
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Components
var mock = new Mock();
var logger = Mock.Of();
- var typeFinder = new TypeFinder(logger);
+ var typeFinder = TestHelper.GetTypeFinder();
var f = new UmbracoDatabaseFactory(logger, new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator);
var fs = new FileSystems(mock.Object, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings());
var coreDebug = Mock.Of();
@@ -371,14 +371,15 @@ namespace Umbraco.Tests.Components
public void AllComposers()
{
var ioHelper = TestHelper.IOHelper;
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var typeLoader = new TypeLoader(ioHelper, typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
var register = MockRegister();
var composition = new Composition(register, typeLoader, Mock.Of(),
MockRuntimeState(RuntimeLevel.Run), Configs, TestHelper.IOHelper, AppCaches.NoCache);
- var types = typeLoader.GetTypes().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web"));
+ var allComposers = typeLoader.GetTypes().ToList();
+ var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList();
var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of());
var requirements = composers.GetRequirements();
var report = Composers.GetComposersReport(requirements);
diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
index ac7dd8be2a..6c5ccd5510 100644
--- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs
+++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
@@ -22,7 +22,7 @@ namespace Umbraco.Tests.Composing
{
ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of());
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
TypeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan);
}
diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests/Composing/CompositionTests.cs
index 4dfaf6871d..ce3cdfac17 100644
--- a/src/Umbraco.Tests/Composing/CompositionTests.cs
+++ b/src/Umbraco.Tests/Composing/CompositionTests.cs
@@ -38,7 +38,7 @@ namespace Umbraco.Tests.Composing
.Returns(() => factoryFactory?.Invoke(mockedFactory));
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
var typeLoader = new TypeLoader(ioHelper, typeFinder, Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of(), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache);
diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
index 5fe4c241d6..3bdfd09752 100644
--- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
@@ -57,7 +57,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void Find_Class_Of_Type_With_Attribute()
{
- var typeFinder = new TypeFinder(GetTestProfilingLogger());
+ var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies);
Assert.AreEqual(2, typesFound.Count());
}
@@ -65,12 +65,15 @@ namespace Umbraco.Tests.Composing
[Test]
public void Find_Classes_With_Attribute()
{
- var typeFinder = new TypeFinder(GetTestProfilingLogger());
+ var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
var typesFound = typeFinder.FindClassesWithAttribute(_assemblies);
Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree]
typesFound = typeFinder.FindClassesWithAttribute(new[] { typeof (UmbracoContext).Assembly });
Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
+
+ typesFound = typeFinder.FindClassesWithAttribute();
+ Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
}
private static IProfilingLogger GetTestProfilingLogger()
diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
index 6658c689e1..d0181563a8 100644
--- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Composing
public void Initialize()
{
// this ensures it's reset
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
_typeLoader = new TypeLoader(TestHelper.IOHelper, typeFinder, NoAppCache.Instance,
new DirectoryInfo(TestHelper.IOHelper.MapPath("~/App_Data/TEMP")),
new ProfilingLogger(Mock.Of(), Mock.Of()), false,
diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs
index 66adfc4a97..d6ed8f33c2 100644
--- a/src/Umbraco.Tests/Macros/MacroTests.cs
+++ b/src/Umbraco.Tests/Macros/MacroTests.cs
@@ -17,7 +17,7 @@ namespace Umbraco.Tests.Macros
[SetUp]
public void Setup()
{
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
//we DO want cache enabled for these tests
var cacheHelper = new AppCaches(
new ObjectCacheAppCache(typeFinder),
diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs
index d5117c6a69..07b7ae7cba 100644
--- a/src/Umbraco.Tests/Models/ContentTests.cs
+++ b/src/Umbraco.Tests/Models/ContentTests.cs
@@ -22,6 +22,7 @@ using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Tests.Testing;
using Umbraco.Web.PropertyEditors;
+using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Models
{
@@ -269,7 +270,8 @@ namespace Umbraco.Tests.Models
content.UpdateDate = DateTime.Now;
content.WriterId = 23;
- var runtimeCache = new ObjectCacheAppCache(new TypeFinder(Mock.Of()));
+ var typeFinder = TestHelper.GetTypeFinder();
+ var runtimeCache = new ObjectCacheAppCache(typeFinder);
runtimeCache.Insert(content.Id.ToString(CultureInfo.InvariantCulture), () => content);
var proflog = GetTestProfilingLogger();
diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
index d3e6dae26b..769985d515 100644
--- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
+++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
@@ -127,7 +127,7 @@ namespace Umbraco.Tests.Published
var setType1 = publishedContentTypeFactory.CreateContentType(1000, "set1", CreatePropertyTypes);
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var elementsCache = new FastDictionaryAppCache(typeFinder);
var snapshotCache = new FastDictionaryAppCache(typeFinder);
diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs
index c1f571aa91..bea0dce979 100644
--- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs
@@ -143,7 +143,7 @@ namespace Umbraco.Tests.PublishedContent
// create a data source for NuCache
_source = new TestDataSource(kits);
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var settings = Mock.Of();
diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs
index c5c2f678ee..7abd4179f0 100644
--- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs
@@ -184,7 +184,7 @@ namespace Umbraco.Tests.PublishedContent
// create a variation accessor
_variationAccesor = new TestVariationContextAccessor();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var settings = Mock.Of();
// at last, create the complete NuCache snapshot service!
diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
index e4d0e596ae..9fb77ef59d 100644
--- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
+++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
@@ -125,6 +125,10 @@ namespace Umbraco.Tests.Runtimes
}
+ // override because we cannot use Assembly.GetEntryAssembly in Nunit tests since that is always null
+ protected override ITypeFinder GetTypeFinder()
+ => new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
+
// must override the database factory
// else BootFailedException because U cannot connect to the configured db
protected internal override IUmbracoDatabaseFactory GetDatabaseFactory()
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 225506093e..2560ae8e94 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -63,7 +63,7 @@ namespace Umbraco.Tests.Runtimes
var profilingLogger = new ProfilingLogger(logger, profiler);
var appCaches = AppCaches.Disabled;
var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy(() => factory.GetInstance()), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator);
- var typeFinder = new TypeFinder(logger);
+ var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
var ioHelper = TestHelper.IOHelper;
var hostingEnvironment = Mock.Of();
var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
@@ -256,7 +256,7 @@ namespace Umbraco.Tests.Runtimes
var profilingLogger = new ProfilingLogger(logger, profiler);
var appCaches = AppCaches.Disabled;
var databaseFactory = Mock.Of();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
var runtimeState = Mock.Of();
diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs
index 7a388417bc..41c8d59105 100644
--- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs
+++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs
@@ -85,7 +85,7 @@ namespace Umbraco.Tests.Scoping
var memberRepository = Mock.Of();
var hostingEnvironment = TestHelper.GetHostingEnvironment();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var settings = Mock.Of();
return new PublishedSnapshotService(
diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs
index 1b6b632a10..33e8b0010e 100644
--- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs
+++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs
@@ -58,7 +58,7 @@ namespace Umbraco.Tests.Services
var memberRepository = Mock.Of();
var hostingEnvironment = Mock.Of();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var settings = Mock.Of();
return new PublishedSnapshotService(
diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
index 2bd36947c6..e035eaa807 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
@@ -38,7 +38,7 @@ namespace Umbraco.Tests.TestHelpers
var ioHelper = TestHelper.IOHelper;
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var typeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance,
new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")),
logger,
diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
index c79a0f5c47..f5d18e05ba 100644
--- a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
+++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs
{
if (_factory != null) return _factory(requestContext);
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var types = typeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() });
var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));
diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
index 309ba9a5fc..b201959de6 100644
--- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
@@ -43,6 +43,14 @@ namespace Umbraco.Tests.TestHelpers
public static class TestHelper
{
+ public static ITypeFinder GetTypeFinder()
+ {
+
+ var typeFinder = new TypeFinder(Mock.Of(),
+ new DefaultUmbracoAssemblyProvider(typeof(TestHelper).Assembly));
+ return typeFinder;
+ }
+
public static TypeLoader GetMockedTypeLoader()
{
return new TypeLoader(IOHelper, Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of());
diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
index 2af409e024..bb342c9939 100644
--- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
@@ -247,7 +247,7 @@ namespace Umbraco.Tests.TestHelpers
databaseFactory = new UmbracoDatabaseFactory(Constants.System.UmbracoConnectionName, logger, new Lazy(() => mappers), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator);
}
- typeFinder = typeFinder ?? new TypeFinder(logger);
+ typeFinder = typeFinder ?? new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
fileSystems = fileSystems ?? new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings());
var coreDebug = Current.Configs.CoreDebug();
var mediaFileSystem = Mock.Of();
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index 41c05276fb..58a6fa6d41 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -171,7 +171,7 @@ namespace Umbraco.Tests.Testing
var proflogger = new ProfilingLogger(logger, profiler);
IOHelper = TestHelper.IOHelper;
- TypeFinder = new TypeFinder(logger);
+ TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
var appCaches = GetAppCaches();
var globalSettings = SettingsForTests.GetDefaultGlobalSettings();
var settings = SettingsForTests.GenerateMockWebRoutingSettings();
diff --git a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
index b479961896..62d7e941d7 100644
--- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
+++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Web
{
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
var container = new Mock();
- var typeFinder = new TypeFinder(Mock.Of());
+ var typeFinder = TestHelper.GetTypeFinder();
var ioHelper = TestHelper.IOHelper;
container
.Setup(x => x.GetInstance(typeof(TypeLoader)))
diff --git a/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs b/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs
deleted file mode 100644
index 994e8c26c4..0000000000
--- a/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Security;
-using System.Web.Compilation;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Composing;
-using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.Hosting;
-using Umbraco.Core.IO;
-using Umbraco.Core.Logging;
-
-namespace Umbraco.Web.Composing
-{
- ///
- /// An implementation of TypeFinder that uses the BuildManager to resolve references for aspnet framework hosted websites
- ///
- ///
- /// This finder will also try to resolve dynamic assemblies created from App_Code
- ///
- internal class BuildManagerTypeFinder : TypeFinder, ITypeFinder
- {
-
- public BuildManagerTypeFinder(
- IIOHelper ioHelper,
- IHostingEnvironment hostingEnvironment,
- ILogger logger,
- ITypeFinderConfig typeFinderConfig = null) : base(logger, typeFinderConfig)
- {
- if (ioHelper == null) throw new ArgumentNullException(nameof(ioHelper));
- if (hostingEnvironment == null) throw new ArgumentNullException(nameof(hostingEnvironment));
- if (logger == null) throw new ArgumentNullException(nameof(logger));
-
- _allAssemblies = new Lazy>(() =>
- {
- var isHosted = hostingEnvironment.IsHosted;
- try
- {
- if (isHosted)
- {
- var assemblies = new HashSet(BuildManager.GetReferencedAssemblies().Cast());
-
- //here we are trying to get the App_Code assembly
- var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
- var appCodeFolder = new DirectoryInfo(ioHelper.MapPath(ioHelper.ResolveUrl("~/App_code")));
- //check if the folder exists and if there are any files in it with the supported file extensions
- if (appCodeFolder.Exists && fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any()))
- {
- try
- {
- var appCodeAssembly = Assembly.Load("App_Code");
- if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already
- assemblies.Add(appCodeAssembly);
- }
- catch (FileNotFoundException ex)
- {
- //this will occur if it cannot load the assembly
- logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
- }
- }
- }
- }
- catch (InvalidOperationException e)
- {
- if (e.InnerException is SecurityException == false)
- throw;
- }
-
- // Not hosted, just use the default implementation
- return new HashSet(base.AssembliesToScan);
- });
- }
-
- private readonly Lazy> _allAssemblies;
-
- ///
- /// Explicitly implement and return result from BuildManager
- ///
- ///
- ///
- Type ITypeFinder.GetTypeByName (string name) => BuildManager.GetType(name, false);
-
- ///
- /// Explicitly implement and return result from BuildManager
- ///
- IEnumerable ITypeFinder.AssembliesToScan => _allAssemblies.Value;
-
- ///
- /// TypeFinder config via appSettings
- ///
- internal class TypeFinderConfig : ITypeFinderConfig
- {
- private readonly ITypeFinderSettings _settings;
- private IEnumerable _assembliesAcceptingLoadExceptions;
-
- public TypeFinderConfig(ITypeFinderSettings settings)
- {
- _settings = settings;
- }
-
- public IEnumerable AssembliesAcceptingLoadExceptions
- {
- get
- {
- if (_assembliesAcceptingLoadExceptions != null)
- return _assembliesAcceptingLoadExceptions;
-
- var s = _settings.AssembliesAcceptingLoadExceptions;
- return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
- ? Array.Empty()
- : s.Split(',').Select(x => x.Trim()).ToArray();
- }
- }
- }
- }
-}
diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs
index 582f35db70..ea08dc9135 100644
--- a/src/Umbraco.Web/Runtime/WebRuntime.cs
+++ b/src/Umbraco.Web/Runtime/WebRuntime.cs
@@ -21,8 +21,6 @@ namespace Umbraco.Web.Runtime
/// On top of CoreRuntime, handles all of the web-related runtime aspects of Umbraco.
public class WebRuntime : CoreRuntime
{
- private BuildManagerTypeFinder _typeFinder;
-
///
/// Initializes a new instance of the class.
///
@@ -92,8 +90,6 @@ namespace Umbraco.Web.Runtime
#region Getters
- protected override ITypeFinder GetTypeFinder() => _typeFinder ?? (_typeFinder = new BuildManagerTypeFinder(IOHelper, HostingEnvironment, Logger, new BuildManagerTypeFinder.TypeFinderConfig(new TypeFinderSettings())));
-
protected override AppCaches GetAppCaches() => new AppCaches(
// we need to have the dep clone runtime cache provider to ensure
// all entities are cached properly (cloned in and cloned out)
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 504f36786a..df6233431a 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -143,7 +143,6 @@
-