diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Abstractions/Cache/FastDictionaryAppCache.cs
similarity index 97%
rename from src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
rename to src/Umbraco.Abstractions/Cache/FastDictionaryAppCache.cs
index b38f36a7d8..3bd29c3f5f 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
+++ b/src/Umbraco.Abstractions/Cache/FastDictionaryAppCache.cs
@@ -10,13 +10,15 @@ namespace Umbraco.Core.Cache
///
/// Implements a fast on top of a concurrent dictionary.
///
- internal class FastDictionaryAppCache : IAppCache
+ public class FastDictionaryAppCache : IAppCache
{
///
/// Gets the internal items dictionary, for tests only!
///
internal readonly ConcurrentDictionary> Items = new ConcurrentDictionary>();
+ public int Count => Items.Count;
+
///
public object Get(string cacheKey)
{
@@ -76,7 +78,7 @@ namespace Umbraco.Core.Cache
///
public void ClearOfType(string typeName)
{
- var type = TypeFinder.GetTypeByName(typeName);
+ var type = TypeHelper.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Abstractions/Cache/FastDictionaryAppCacheBase.cs
similarity index 98%
rename from src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
rename to src/Umbraco.Abstractions/Cache/FastDictionaryAppCacheBase.cs
index eb84423f32..b49ecea671 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
+++ b/src/Umbraco.Abstractions/Cache/FastDictionaryAppCacheBase.cs
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Cache
///
/// Provides a base class to fast, dictionary-based implementations.
///
- internal abstract class FastDictionaryAppCacheBase : IAppCache
+ public abstract class FastDictionaryAppCacheBase : IAppCache
{
// prefix cache keys so we know which one are ours
protected const string CacheItemPrefix = "umbrtmche";
@@ -116,7 +116,7 @@ namespace Umbraco.Core.Cache
///
public virtual void ClearOfType(string typeName)
{
- var type = TypeFinder.GetTypeByName(typeName);
+ var type = TypeHelper.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Abstractions/Cache/ObjectCacheAppCache.cs
similarity index 99%
rename from src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
rename to src/Umbraco.Abstractions/Cache/ObjectCacheAppCache.cs
index ad7f3d6bf7..7d5081baa5 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
+++ b/src/Umbraco.Abstractions/Cache/ObjectCacheAppCache.cs
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Cache
///
/// Gets the internal memory cache, for tests only!
///
- internal ObjectCache MemoryCache { get; private set; }
+ public ObjectCache MemoryCache { get; private set; }
///
public object Get(string key)
@@ -178,7 +178,7 @@ namespace Umbraco.Core.Cache
///
public virtual void ClearOfType(string typeName)
{
- var type = TypeFinder.GetTypeByName(typeName);
+ var type = TypeHelper.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Abstractions/Composing/TypeHelper.cs b/src/Umbraco.Abstractions/Composing/TypeHelper.cs
index 40a1adc118..768709c44c 100644
--- a/src/Umbraco.Abstractions/Composing/TypeHelper.cs
+++ b/src/Umbraco.Abstractions/Composing/TypeHelper.cs
@@ -8,6 +8,7 @@ using System.Reflection;
namespace Umbraco.Core.Composing
{
+
///
/// A utility class for type checking, this provides internal caching so that calls to these methods will be faster
/// than doing a manual type check in c#
@@ -21,6 +22,66 @@ namespace Umbraco.Core.Composing
private static readonly Assembly[] EmptyAssemblies = new Assembly[0];
+ ///
+ /// Returns a Type for the string type name
+ ///
+ ///
+ ///
+ public static Type GetTypeByName(string name)
+ {
+ var type = Type.GetType(name);
+ if (type != null) return type;
+
+ // now try fall back procedures. null may be returned because Type.GetName only returns types that have already been loaded in the appdomain
+ // and this type might not be there yet, so we need to parse the type name and then try to load in via assembly.
+
+ var typeName = TypeName.Parse(name);
+ try
+ {
+ var assembly = Assembly.Load(typeName.AssemblyName);
+ type = assembly.GetType(typeName.Name);
+ return type;
+ }
+ catch (NotSupportedException)
+ {
+ throw;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Used to parse a fully qualified type name
+ ///
+ ///
+ /// Does not support generics.
+ /// This is a simple utility class and is not an exhaustive type name parser (which doesn't exist in .net strangely)
+ ///
+ private class TypeName
+ {
+ private TypeName(string name, AssemblyName assemblyName)
+ {
+ Name = name;
+ AssemblyName = assemblyName;
+ }
+
+ public static TypeName Parse(string name)
+ {
+ if (name.Contains("[["))
+ throw new NotSupportedException($"{nameof(TypeName)} does not support generic types");
+
+ var index = name.IndexOf(',');
+ return index > 0
+ ? new TypeName(name.Substring(0, index).Trim(), new AssemblyName(name.Substring(index + 1).Trim()))
+ : new TypeName(name, null);
+ }
+
+ public string Name { get; }
+ public AssemblyName AssemblyName { get; }
+ }
+
///
/// Based on a type we'll check if it is IEnumerable{T} (or similar) and if so we'll return a List{T}, this will also deal with array types and return List{T} for those too.
/// If it cannot be done, null is returned.
diff --git a/src/Umbraco.Core/Composing/ITypeFinder.cs b/src/Umbraco.Core/Composing/ITypeFinder.cs
new file mode 100644
index 0000000000..844719b782
--- /dev/null
+++ b/src/Umbraco.Core/Composing/ITypeFinder.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ public interface ITypeFinder
+ {
+ ///
+ /// Return a list of found local Assemblies that Umbraco should scan for type finding
+ ///
+ ///
+ IEnumerable AssembliesToScan { get; }
+
+ ///
+ /// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ IEnumerable FindClassesOfTypeWithAttribute(
+ Type assignTypeFrom,
+ Type attributeType,
+ IEnumerable assemblies = null,
+ bool onlyConcreteClasses = true);
+
+ ///
+ /// Returns all types found of in the assemblies specified of type T
+ ///
+ ///
+ ///
+ ///
+ ///
+ IEnumerable FindClassesOfType(Type assignTypeFrom, IEnumerable assemblies = null, bool onlyConcreteClasses = true);
+
+ ///
+ /// Finds any classes with the attribute.
+ ///
+ /// The attribute type
+ /// The assemblies.
+ /// if set to true only concrete classes.
+ ///
+ IEnumerable FindClassesWithAttribute(
+ Type attributeType,
+ IEnumerable assemblies,
+ bool onlyConcreteClasses);
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs
index 5ad1e43580..a1b1bf2fef 100644
--- a/src/Umbraco.Core/Composing/TypeFinder.cs
+++ b/src/Umbraco.Core/Composing/TypeFinder.cs
@@ -6,11 +6,9 @@ using System.Linq;
using System.Reflection;
using System.Security;
using System.Text;
-using System.Web;
using System.Web.Compilation;
-using System.Web.Hosting;
-using Umbraco.Core.Composing;
using Umbraco.Core.IO;
+using Umbraco.Core.Logging;
namespace Umbraco.Core.Composing
{
@@ -18,14 +16,107 @@ namespace Umbraco.Core.Composing
/// A utility class to find all classes of a certain type by reflection in the current bin folder
/// of the web application.
///
- public static class TypeFinder
+ public class TypeFinder : ITypeFinder
{
- private static volatile HashSet _localFilteredAssemblyCache;
- private static readonly object LocalFilteredAssemblyCacheLocker = new object();
- private static readonly List NotifiedLoadExceptionAssemblies = new List();
- private static string[] _assembliesAcceptingLoadExceptions;
+ private readonly ILogger _logger;
- private static string[] AssembliesAcceptingLoadExceptions
+ public TypeFinder(ILogger logger)
+ {
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _allAssemblies = new Lazy>(() =>
+ {
+ HashSet assemblies = null;
+ try
+ {
+ var isHosted = IOHelper.IsHosted;
+
+ try
+ {
+ if (isHosted)
+ {
+ assemblies = new HashSet(BuildManager.GetReferencedAssemblies().Cast());
+ }
+ }
+ catch (InvalidOperationException e)
+ {
+ if (e.InnerException is SecurityException == false)
+ throw;
+ }
+
+ if (assemblies == null)
+ {
+ //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 = IOHelper.GetRootDirectoryBinFolder();
+ 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);
+ }
+
+ //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;
+ }
+
+ return assemblies;
+ });
+ }
+
+ //Lazy access to the all assemblies list
+ private readonly Lazy> _allAssemblies;
+ private volatile HashSet _localFilteredAssemblyCache;
+ private readonly object _localFilteredAssemblyCacheLocker = new object();
+ private readonly List _notifiedLoadExceptionAssemblies = new List();
+ private string[] _assembliesAcceptingLoadExceptions;
+
+ private string[] AssembliesAcceptingLoadExceptions
{
get
{
@@ -39,7 +130,7 @@ namespace Umbraco.Core.Composing
}
}
- private static bool AcceptsLoadExceptions(Assembly a)
+ private bool AcceptsLoadExceptions(Assembly a)
{
if (AssembliesAcceptingLoadExceptions.Length == 0)
return false;
@@ -67,118 +158,25 @@ namespace Umbraco.Core.Composing
/// 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
///
- internal static HashSet GetAllAssemblies()
+ private IEnumerable GetAllAssemblies()
{
- return AllAssemblies.Value;
+ return _allAssemblies.Value;
}
- //Lazy access to the all assemblies list
- private static readonly Lazy> AllAssemblies = new Lazy>(() =>
+ ///
+ public IEnumerable AssembliesToScan
{
- HashSet assemblies = null;
- try
+ get
{
- var isHosted = IOHelper.IsHosted;
-
- try
+ lock (_localFilteredAssemblyCacheLocker)
{
- if (isHosted)
- {
- assemblies = new HashSet(BuildManager.GetReferencedAssemblies().Cast());
- }
- }
- catch (InvalidOperationException e)
- {
- if (e.InnerException is SecurityException == false)
- throw;
- }
+ if (_localFilteredAssemblyCache != null)
+ return _localFilteredAssemblyCache;
- if (assemblies == null)
- {
- //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 = IOHelper.GetRootDirectoryBinFolder();
- 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;
- }
- }
- }
- }
-
- //if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
- if (assemblies.Any() == false)
- {
- foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
- {
- assemblies.Add(a);
- }
- }
-
- //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
- Current.Logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
- }
- }
- }
- catch (InvalidOperationException e)
- {
- if (e.InnerException is SecurityException == false)
- throw;
- }
-
- return assemblies;
- });
-
- ///
- /// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
- /// and excluding the ones passed in and excluding the exclusion list filter, the results of this are
- /// cached for performance reasons.
- ///
- ///
- ///
- internal static HashSet GetAssembliesWithKnownExclusions(
- IEnumerable excludeFromResults = null)
- {
- lock (LocalFilteredAssemblyCacheLocker)
- {
- if (_localFilteredAssemblyCache != null)
+ var assemblies = GetFilteredAssemblies(null, KnownAssemblyExclusionFilter);
+ _localFilteredAssemblyCache = new HashSet(assemblies);
return _localFilteredAssemblyCache;
-
- var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
- _localFilteredAssemblyCache = new HashSet(assemblies);
- return _localFilteredAssemblyCache;
+ }
}
}
@@ -188,7 +186,7 @@ namespace Umbraco.Core.Composing
///
///
///
- private static IEnumerable GetFilteredAssemblies(
+ private IEnumerable GetFilteredAssemblies(
IEnumerable excludeFromResults = null,
string[] exclusionFilter = null)
{
@@ -210,7 +208,7 @@ 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"
///
- internal static readonly string[] KnownAssemblyExclusionFilter = {
+ private static readonly string[] KnownAssemblyExclusionFilter = {
"Antlr3.",
"AutoMapper,",
"AutoMapper.",
@@ -261,115 +259,40 @@ namespace Umbraco.Core.Composing
};
///
- /// Finds any classes derived from the type T that contain the attribute TAttribute
+ /// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfTypeWithAttribute()
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true);
- }
-
- ///
- /// Finds any classes derived from the type T that contain the attribute TAttribute
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies)
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(assemblies, true);
- }
-
- ///
- /// Finds any classes derived from the type T that contain the attribute TAttribute
- ///
- ///
- ///
+ ///
+ ///
///
///
///
- public static IEnumerable FindClassesOfTypeWithAttribute(
- IEnumerable assemblies,
- bool onlyConcreteClasses)
- where TAttribute : Attribute
+ public IEnumerable FindClassesOfTypeWithAttribute(
+ Type assignTypeFrom,
+ Type attributeType,
+ IEnumerable assemblies = null,
+ bool onlyConcreteClasses = true)
{
- return FindClassesOfTypeWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
+ var assemblyList = (assemblies ?? AssembliesToScan).ToList();
+
+ return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses,
+ //the additional filter will ensure that any found types also have the attribute applied.
+ t => t.GetCustomAttributes(attributeType, false).Any());
}
///
- /// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
+ /// Returns all types found of in the assemblies specified of type T
///
- ///
///
///
///
///
- public static IEnumerable FindClassesOfTypeWithAttribute(
- Type assignTypeFrom,
- IEnumerable assemblies,
- bool onlyConcreteClasses)
- where TAttribute : Attribute
+ public IEnumerable FindClassesOfType(Type assignTypeFrom, IEnumerable assemblies = null, bool onlyConcreteClasses = true)
{
- if (assemblies == null) throw new ArgumentNullException(nameof(assemblies));
+ var assemblyList = (assemblies ?? AssembliesToScan).ToList();
- return GetClassesWithBaseType(assignTypeFrom, assemblies, onlyConcreteClasses,
- //the additional filter will ensure that any found types also have the attribute applied.
- t => t.GetCustomAttributes(false).Any());
+ return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses);
}
-
- ///
- /// Searches all filtered local assemblies specified for classes of the type passed in.
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType()
- {
- return FindClassesOfType(GetAssembliesWithKnownExclusions(), true);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies, bool onlyConcreteClasses)
- {
- if (assemblies == null) throw new ArgumentNullException(nameof(assemblies));
-
- return GetClassesWithBaseType(typeof(T), assemblies, onlyConcreteClasses);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies)
- {
- return FindClassesOfType(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- /// if set to true only concrete classes.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
- where T : Attribute
- {
- return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
- }
-
+
///
/// Finds any classes with the attribute.
///
@@ -377,40 +300,19 @@ namespace Umbraco.Core.Composing
/// The assemblies.
/// if set to true only concrete classes.
///
- public static IEnumerable FindClassesWithAttribute(
+ public IEnumerable FindClassesWithAttribute(
Type attributeType,
- IEnumerable assemblies,
- bool onlyConcreteClasses)
+ IEnumerable assemblies = null,
+ bool onlyConcreteClasses = true)
{
- return GetClassesWithAttribute(attributeType, assemblies, onlyConcreteClasses);
- }
+ var assemblyList = (assemblies ?? AssembliesToScan).ToList();
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies)
- where T : Attribute
- {
- return FindClassesWithAttribute(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute in filtered local assemblies
- ///
- ///
- ///
- public static IEnumerable FindClassesWithAttribute()
- where T : Attribute
- {
- return FindClassesWithAttribute(GetAssembliesWithKnownExclusions());
+ return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
}
#region Private methods
- private static IEnumerable GetClassesWithAttribute(
+ private IEnumerable GetClassesWithAttribute(
Type attributeType,
IEnumerable assemblies,
bool onlyConcreteClasses)
@@ -441,7 +343,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
- Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
+ _logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
continue;
}
@@ -477,7 +379,7 @@ namespace Umbraco.Core.Composing
///
/// An additional filter to apply for what types will actually be included in the return value
///
- private static IEnumerable GetClassesWithBaseType(
+ private IEnumerable GetClassesWithBaseType(
Type baseType,
IEnumerable assemblies,
bool onlyConcreteClasses,
@@ -507,7 +409,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
- Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
+ _logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
continue;
}
@@ -533,7 +435,7 @@ namespace Umbraco.Core.Composing
return types;
}
- internal static IEnumerable GetTypesWithFormattedException(Assembly a)
+ private IEnumerable GetTypesWithFormattedException(Assembly a)
{
//if the assembly is dynamic, do not try to scan it
if (a.IsDynamic)
@@ -569,12 +471,12 @@ namespace Umbraco.Core.Composing
if (AcceptsLoadExceptions(a) == false) throw ex;
// log a warning, and return what we can
- lock (NotifiedLoadExceptionAssemblies)
+ lock (_notifiedLoadExceptionAssemblies)
{
- if (NotifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
+ if (_notifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
{
- NotifiedLoadExceptionAssemblies.Add(a.FullName);
- Current.Logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
+ _notifiedLoadExceptionAssemblies.Add(a.FullName);
+ _logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
}
}
return rex.Types.WhereNotNull().ToArray();
@@ -595,8 +497,7 @@ namespace Umbraco.Core.Composing
sb.Append(". ");
sb.Append(loaderException.GetType().FullName);
- var tloadex = loaderException as TypeLoadException;
- if (tloadex != null)
+ if (loaderException is TypeLoadException tloadex)
{
sb.Append(" on ");
sb.Append(tloadex.TypeName);
@@ -609,24 +510,5 @@ namespace Umbraco.Core.Composing
#endregion
- public static Type GetTypeByName(string typeName)
- {
- var type = BuildManager.GetType(typeName, false);
- if (type != null) return type;
-
- // TODO: This isn't very elegant, and will have issues since the AppDomain.CurrentDomain
- // doesn't actualy load in all assemblies, only the types that have been referenced so far.
- // However, in a web context, the BuildManager will have executed which will force all assemblies
- // to be loaded so it's fine for now.
- // It could be fairly easy to parse the typeName to get the assembly name and then do Assembly.Load and
- // find the type from there.
-
- //now try fall back procedures.
- type = Type.GetType(typeName);
- if (type != null) return type;
- return AppDomain.CurrentDomain.GetAssemblies()
- .Select(x => x.GetType(typeName))
- .FirstOrDefault(x => x != null);
- }
}
}
diff --git a/src/Umbraco.Core/Composing/TypeFinderExtensions.cs b/src/Umbraco.Core/Composing/TypeFinderExtensions.cs
new file mode 100644
index 0000000000..e364790556
--- /dev/null
+++ b/src/Umbraco.Core/Composing/TypeFinderExtensions.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ public static class TypeFinderExtensions
+ {
+ ///
+ /// Finds any classes derived from the type T that contain the attribute TAttribute
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable FindClassesOfTypeWithAttribute(this ITypeFinder typeFinder, IEnumerable assemblies = null, bool onlyConcreteClasses = true)
+ where TAttribute : Attribute
+ => typeFinder.FindClassesOfTypeWithAttribute(typeof(T), typeof(TAttribute), assemblies, onlyConcreteClasses);
+
+ ///
+ /// Returns all types found of in the assemblies specified of type T
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable FindClassesOfType(this ITypeFinder typeFinder, IEnumerable assemblies = null, bool onlyConcreteClasses = true)
+ => typeFinder.FindClassesOfType(typeof(T), assemblies, onlyConcreteClasses);
+
+ ///
+ /// Finds the classes with attribute.
+ ///
+ ///
+ ///
+ /// The assemblies.
+ /// if set to true only concrete classes.
+ ///
+ public static IEnumerable FindClassesWithAttribute(this ITypeFinder typeFinder, IEnumerable assemblies = null, bool onlyConcreteClasses = true)
+ where T : Attribute
+ => typeFinder.FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs
index fe7a561eca..daa95ede49 100644
--- a/src/Umbraco.Core/Composing/TypeLoader.cs
+++ b/src/Umbraco.Core/Composing/TypeLoader.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Composing
/// Provides methods to find and instantiate types.
///
///
- /// This class should be used to get all types, the class should never be used directly.
+ /// This class should be used to get all types, the class should never be used directly.
/// In most cases this class is not used directly but through extension methods that retrieve specific types.
/// This class caches the types it knows to avoid excessive assembly scanning and shorten startup times, relying
/// on a hash of the DLLs in the ~/bin folder to check for cache expiration.
@@ -48,22 +48,25 @@ namespace Umbraco.Core.Composing
///
/// Initializes a new instance of the class.
///
+ ///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
- public TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger)
- : this(runtimeCache, localTempPath, logger, true)
+ public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger)
+ : this(typeFinder, runtimeCache, localTempPath, logger, true)
{ }
///
/// Initializes a new instance of the class.
///
+ ///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
/// Whether to detect changes using hashes.
- internal TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger, bool detectChanges)
+ internal TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger, bool detectChanges)
{
+ TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_localTempPath = localTempPath;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -105,6 +108,12 @@ namespace Umbraco.Core.Composing
internal TypeLoader()
{ }
+ ///
+ /// Returns the underlying
+ ///
+ // ReSharper disable once MemberCanBePrivate.Global
+ public ITypeFinder TypeFinder { get; }
+
///
/// Gets or sets the set of assemblies to scan.
///
@@ -117,7 +126,7 @@ namespace Umbraco.Core.Composing
// internal for tests
internal IEnumerable AssembliesToScan
{
- get => _assemblies ?? (_assemblies = TypeFinder.GetAssembliesWithKnownExclusions());
+ get => _assemblies ?? (_assemblies = TypeFinder.AssembliesToScan);
set => _assemblies = value;
}
diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs
index 5b069641c4..8ccb740cc2 100644
--- a/src/Umbraco.Core/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs
@@ -111,8 +111,9 @@ namespace Umbraco.Core.Runtime
// configs
var configs = GetConfigs();
- // type loader
- var typeLoader = new TypeLoader(appCaches.RuntimeCache, configs.Global().LocalTempPath, ProfilingLogger);
+ // type finder/loader
+ var typeFinder = new TypeFinder(Logger);
+ var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, configs.Global().LocalTempPath, ProfilingLogger);
// runtime state
// beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance'
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 5f18cb3d95..87f20eb070 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -125,11 +125,8 @@
-->
-
-
-
@@ -142,7 +139,9 @@
+
+
diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine/LuceneIndexCreator.cs
index 806d0edc7a..97a929c9c8 100644
--- a/src/Umbraco.Examine/LuceneIndexCreator.cs
+++ b/src/Umbraco.Examine/LuceneIndexCreator.cs
@@ -38,7 +38,7 @@ namespace Umbraco.Examine
if (!configuredDirectoryFactory.IsNullOrWhiteSpace())
{
//this should be a fully qualified type
- var factoryType = TypeFinder.GetTypeByName(configuredDirectoryFactory);
+ var factoryType = TypeHelper.GetTypeByName(configuredDirectoryFactory);
if (factoryType == null) throw new NullReferenceException("No directory type found for value: " + configuredDirectoryFactory);
var directoryFactory = (IDirectoryFactory)Activator.CreateInstance(factoryType);
return directoryFactory.CreateDirectory(dirInfo);
diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs
index 2ba94d8c78..2bd0d5d471 100644
--- a/src/Umbraco.Tests/Components/ComponentTests.cs
+++ b/src/Umbraco.Tests/Components/ComponentTests.cs
@@ -361,7 +361,8 @@ namespace Umbraco.Tests.Components
[Test]
public void AllComposers()
{
- var typeLoader = new TypeLoader(AppCaches.Disabled.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of());
+ var typeFinder = new TypeFinder(Mock.Of());
+ var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of());
var register = MockRegister();
var composition = new Composition(register, typeLoader, Mock.Of(), MockRuntimeState(RuntimeLevel.Run));
diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
index ef364afd38..4b5be30cd9 100644
--- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs
+++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs
@@ -22,7 +22,8 @@ namespace Umbraco.Tests.Composing
{
ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of());
- TypeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), ProfilingLogger, detectChanges: false)
+ var typeFinder = new TypeFinder(Mock.Of());
+ TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), ProfilingLogger, detectChanges: false)
{
AssembliesToScan = AssembliesToScan
};
diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests/Composing/CompositionTests.cs
index 33855a8bfb..9668d7619a 100644
--- a/src/Umbraco.Tests/Composing/CompositionTests.cs
+++ b/src/Umbraco.Tests/Composing/CompositionTests.cs
@@ -36,7 +36,8 @@ namespace Umbraco.Tests.Composing
.Returns(() => factoryFactory?.Invoke(mockedFactory));
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
- var typeLoader = new TypeLoader(Mock.Of(), IOHelper.MapPath("~/App_Data/TEMP"), logger);
+ var typeFinder = new TypeFinder(Mock.Of());
+ var typeLoader = new TypeLoader(typeFinder, Mock.Of(), IOHelper.MapPath("~/App_Data/TEMP"), logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of());
// create the factory, ensure it is the mocked factory
diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
index ca622e9288..fd070dee2a 100644
--- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs
@@ -10,6 +10,7 @@ using System.Text;
using System.Threading;
using System.Web;
using System.Web.Compilation;
+using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Composing;
@@ -56,39 +57,19 @@ namespace Umbraco.Tests.Composing
[Test]
public void Find_Class_Of_Type_With_Attribute()
{
-
- var typesFound = TypeFinder.FindClassesOfTypeWithAttribute(_assemblies);
+ var typeFinder = new TypeFinder(GetTestProfilingLogger());
+ var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies);
Assert.AreEqual(2, typesFound.Count());
}
- //[Test]
- //public void Find_Classes_Of_Type()
- //{
- // var typesFound = TypeFinder.FindClassesOfType(_assemblies);
- // var originalTypesFound = TypeFinderOriginal.FindClassesOfType(_assemblies);
-
- // foreach (var type in typesFound)
- // Console.WriteLine(type);
- // Console.WriteLine();
- // foreach (var type in originalTypesFound)
- // Console.WriteLine(type);
-
- // // 6 classes in _assemblies implement IApplicationEventHandler
- // Assert.AreEqual(6, typesFound.Count());
-
- // // however,
- // // Umbraco.Core.Profiling.WebProfiler is internal and is not returned by TypeFinderOriginal,
- // // that's a known issue of the legacy type finder, so we have to tweak the count here.
- // Assert.AreEqual(5, originalTypesFound.Count());
- //}
-
[Test]
public void Find_Classes_With_Attribute()
{
- var typesFound = TypeFinder.FindClassesWithAttribute(_assemblies);
+ var typeFinder = new TypeFinder(GetTestProfilingLogger());
+ 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 });
+ typesFound = typeFinder.FindClassesWithAttribute(new[] { typeof (UmbracoContext).Assembly });
Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
}
@@ -122,447 +103,6 @@ namespace Umbraco.Tests.Composing
}
- //USED FOR THE ABOVE TESTS
- // see this issue for details: http://issues.umbraco.org/issue/U4-1187
- internal static class TypeFinderOriginal
- {
-
- private static readonly ConcurrentBag LocalFilteredAssemblyCache = new ConcurrentBag();
- private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
- private static ReadOnlyCollection _allAssemblies = null;
- private static ReadOnlyCollection _binFolderAssemblies = null;
- private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
-
- ///
- /// 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
- ///
- internal static IEnumerable GetAllAssemblies()
- {
- if (_allAssemblies == null)
- {
- using (new WriteLock(Locker))
- {
- List assemblies = null;
- try
- {
- var isHosted = HttpContext.Current != null;
-
- try
- {
- if (isHosted)
- {
- assemblies = new List(BuildManager.GetReferencedAssemblies().Cast());
- }
- }
- catch (InvalidOperationException e)
- {
- if (!(e.InnerException is SecurityException))
- throw;
- }
-
-
- if (assemblies == null)
- {
- //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 = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
- var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- assemblies = new List();
- 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;
- }
- }
- }
- }
-
- //if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
- if (!assemblies.Any())
- {
- assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
- }
-
- //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())))
- {
- var appCodeAssembly = Assembly.Load("App_Code");
- if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
- assemblies.Add(appCodeAssembly);
- }
-
- //now set the _allAssemblies
- _allAssemblies = new ReadOnlyCollection(assemblies);
-
- }
- catch (InvalidOperationException e)
- {
- if (!(e.InnerException is SecurityException))
- throw;
-
- _binFolderAssemblies = _allAssemblies;
- }
- }
- }
-
- return _allAssemblies;
- }
-
- ///
- /// Returns only assemblies found in the bin folder that have been loaded into the app domain.
- ///
- ///
- ///
- /// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
- ///
- internal static IEnumerable GetBinAssemblies()
- {
-
- if (_binFolderAssemblies == null)
- {
- using (new WriteLock(Locker))
- {
- var assemblies = GetAssembliesWithKnownExclusions().ToArray();
- var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
- var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
- var safeDomainAssemblies = new List();
- var binFolderAssemblies = new List();
-
- foreach (var a in assemblies)
- {
- try
- {
- //do a test to see if its queryable in med trust
- var assemblyFile = a.GetAssemblyFile();
- safeDomainAssemblies.Add(a);
- }
- catch (SecurityException)
- {
- //we will just ignore this because this will fail
- //in medium trust for system assemblies, we get an exception but we just want to continue until we get to
- //an assembly that is ok.
- }
- }
-
- foreach (var assemblyName in domainAssemblyNames)
- {
- try
- {
- var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
- if (foundAssembly != null)
- {
- binFolderAssemblies.Add(foundAssembly);
- }
- }
- catch (SecurityException)
- {
- //we will just ignore this because if we are trying to do a call to:
- // AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
- //in medium trust for system assemblies, we get an exception but we just want to continue until we get to
- //an assembly that is ok.
- }
- }
-
- _binFolderAssemblies = new ReadOnlyCollection(binFolderAssemblies);
- }
- }
- return _binFolderAssemblies;
- }
-
- ///
- /// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
- /// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
- /// cached for perforance reasons.
- ///
- ///
- ///
- internal static IEnumerable GetAssembliesWithKnownExclusions(
- IEnumerable excludeFromResults = null)
- {
- if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
- using (new WriteLock(LocalFilteredAssemblyCacheLocker))
- {
- var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
- foreach (var assembly in assemblies) LocalFilteredAssemblyCache.Add(assembly);
- }
- return LocalFilteredAssemblyCache;
- }
-
- ///
- /// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
- ///
- ///
- ///
- ///
- private static IEnumerable GetFilteredAssemblies(
- IEnumerable excludeFromResults = null,
- string[] exclusionFilter = null)
- {
- if (excludeFromResults == null)
- excludeFromResults = new List();
- if (exclusionFilter == null)
- exclusionFilter = new string[] { };
-
- return GetAllAssemblies()
- .Where(x => !excludeFromResults.Contains(x)
- && !x.GlobalAssemblyCache
- && !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
- }
-
- ///
- /// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
- ///
- ///
- /// 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
- ///
- internal static readonly string[] KnownAssemblyExclusionFilter = new[]
- {
- "mscorlib,",
- "System.",
- "Antlr3.",
- "Autofac.",
- "Autofac,",
- "Castle.",
- "ClientDependency.",
- "DataAnnotationsExtensions.",
- "DataAnnotationsExtensions,",
- "Dynamic,",
- "HtmlDiff,",
- "Iesi.Collections,",
- "Microsoft.",
- "Newtonsoft.",
- "NHibernate.",
- "NHibernate,",
- "NuGet.",
- "RouteDebugger,",
- "SqlCE4Umbraco,",
- "umbraco.datalayer,",
- "umbraco.interfaces,",
- "umbraco.providers,",
- "Umbraco.Web.UI,",
- "Lucene.",
- "Examine,",
- "Examine.",
- "ServiceStack.",
- "MySql.",
- "HtmlAgilityPack.",
- "TidyNet.",
- "ICSharpCode.",
- "CookComputing.",
- /* Mono */
- "MonoDevelop.NUnit",
- "Serilog."
- };
-
- public static IEnumerable FindClassesOfTypeWithAttribute()
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true);
- }
-
- public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies)
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(assemblies, true);
- }
-
- public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
- where TAttribute : Attribute
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
-
- var l = new List();
- foreach (var a in assemblies)
- {
- var types = from t in GetTypesWithFormattedException(a)
- where !t.IsInterface
- && typeof(T).IsAssignableFrom(t)
- && t.GetCustomAttributes(false).Any()
- && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
- select t;
- l.AddRange(types);
- }
-
- return l;
- }
-
- ///
- /// Searches all filtered local assemblies specified for classes of the type passed in.
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType()
- {
- return FindClassesOfType(GetAssembliesWithKnownExclusions(), true);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies, bool onlyConcreteClasses)
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
-
- return GetAssignablesFromType(assemblies, onlyConcreteClasses);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies)
- {
- return FindClassesOfType(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- /// if set to true only concrete classes.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
- where T : Attribute
- {
- return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- /// The attribute type
- /// The assemblies.
- /// if set to true only concrete classes.
- ///
- public static IEnumerable FindClassesWithAttribute(Type type, IEnumerable assemblies, bool onlyConcreteClasses)
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
- if (!TypeHelper.IsTypeAssignableFrom(type))
- throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
-
- var l = new List();
- foreach (var a in assemblies)
- {
- var types = from t in GetTypesWithFormattedException(a)
- where !t.IsInterface && t.GetCustomAttributes(type, false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
- select t;
- l.AddRange(types);
- }
-
- return l;
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies)
- where T : Attribute
- {
- return FindClassesWithAttribute(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute in filtered local assemblies
- ///
- ///
- ///
- public static IEnumerable FindClassesWithAttribute()
- where T : Attribute
- {
- return FindClassesWithAttribute(GetAssembliesWithKnownExclusions());
- }
-
-
- #region Private methods
-
- ///
- /// Gets a collection of assignables of type T from a collection of assemblies
- ///
- ///
- ///
- ///
- ///
- private static IEnumerable GetAssignablesFromType(IEnumerable assemblies, bool onlyConcreteClasses)
- {
- return GetTypes(typeof(T), assemblies, onlyConcreteClasses);
- }
-
- private static IEnumerable GetTypes(Type assignTypeFrom, IEnumerable assemblies, bool onlyConcreteClasses)
- {
- var l = new List();
- foreach (var a in assemblies)
- {
- var types = from t in GetTypesWithFormattedException(a)
- where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
- select t;
- l.AddRange(types);
- }
- return l;
- }
-
- private static IEnumerable GetTypesWithFormattedException(Assembly a)
- {
- //if the assembly is dynamic, do not try to scan it
- if (a.IsDynamic)
- return Enumerable.Empty();
-
- try
- {
- return a.GetExportedTypes();
- }
- catch (ReflectionTypeLoadException ex)
- {
- var sb = new StringBuilder();
- sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
- foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
- {
- sb.AppendLine("Exception: " + loaderException.ToString());
- }
- throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
- }
- }
-
- #endregion
-
-
-
- }
}
diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
index 7459ae848b..b135405615 100644
--- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
+++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs
@@ -27,7 +27,8 @@ namespace Umbraco.Tests.Composing
public void Initialize()
{
// this ensures it's reset
- _typeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of()), false);
+ var typeFinder = new TypeFinder(Mock.Of());
+ _typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of()), false);
// for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
// TODO: Should probably update this so it only searches this assembly and add custom types to be found
diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests/CoreThings/UdiTests.cs
index 2770803bea..a6b87ad57b 100644
--- a/src/Umbraco.Tests/CoreThings/UdiTests.cs
+++ b/src/Umbraco.Tests/CoreThings/UdiTests.cs
@@ -26,8 +26,9 @@ namespace Umbraco.Tests.CoreThings
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
var container = new Mock();
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
+ var typeFinder = new TypeFinder(Mock.Of());
container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns(
- new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of())));
+ new TypeLoader(typeFinder, NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of())));
Current.Factory = container.Object;
Udi.ResetUdiTypes();
diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
index 9db539d142..2f009d147e 100644
--- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
+++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs
@@ -144,39 +144,39 @@ namespace Umbraco.Tests.Published
Assert.AreEqual(1, converter.SourceConverts);
Assert.AreEqual(1, converter.InterConverts);
- Assert.AreEqual(elementsCount1, elementsCache.Items.Count);
- Assert.AreEqual(snapshotCount1, snapshotCache.Items.Count);
+ Assert.AreEqual(elementsCount1, elementsCache.Count);
+ Assert.AreEqual(snapshotCount1, snapshotCache.Count);
Assert.AreEqual(1234, set1.Value("prop1"));
Assert.AreEqual(1, converter.SourceConverts);
Assert.AreEqual(interConverts, converter.InterConverts);
- Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
- Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
+ Assert.AreEqual(elementsCount2, elementsCache.Count);
+ Assert.AreEqual(snapshotCount2, snapshotCache.Count);
var oldSnapshotCache = snapshotCache;
- snapshotCache.Items.Clear();
+ snapshotCache.Clear();
Assert.AreEqual(1234, set1.Value("prop1"));
Assert.AreEqual(1, converter.SourceConverts);
- Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
- Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
- Assert.AreEqual(snapshotCount2, oldSnapshotCache.Items.Count);
+ Assert.AreEqual(elementsCount2, elementsCache.Count);
+ Assert.AreEqual(snapshotCount2, snapshotCache.Count);
+ Assert.AreEqual(snapshotCount2, oldSnapshotCache.Count);
- Assert.AreEqual((interConverts == 1 ? 1 : 3) + snapshotCache.Items.Count, converter.InterConverts);
+ Assert.AreEqual((interConverts == 1 ? 1 : 3) + snapshotCache.Count, converter.InterConverts);
var oldElementsCache = elementsCache;
- elementsCache.Items.Clear();
+ elementsCache.Clear();
Assert.AreEqual(1234, set1.Value("prop1"));
Assert.AreEqual(1, converter.SourceConverts);
- Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
- Assert.AreEqual(elementsCount2, oldElementsCache.Items.Count);
- Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
+ Assert.AreEqual(elementsCount2, elementsCache.Count);
+ Assert.AreEqual(elementsCount2, oldElementsCache.Count);
+ Assert.AreEqual(snapshotCount2, snapshotCache.Count);
- Assert.AreEqual((interConverts == 1 ? 1 : 4) + snapshotCache.Items.Count + elementsCache.Items.Count, converter.InterConverts);
+ Assert.AreEqual((interConverts == 1 ? 1 : 4) + snapshotCache.Count + elementsCache.Count, converter.InterConverts);
}
[Test]
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 1f1500137f..a205478246 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -61,7 +61,8 @@ namespace Umbraco.Tests.Runtimes
var profilingLogger = new ProfilingLogger(logger, profiler);
var appCaches = AppCaches.Disabled;
var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy(() => factory.GetInstance()));
- var typeLoader = new TypeLoader(appCaches.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
+ var typeFinder = new TypeFinder(logger);
+ var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
var mainDom = new SimpleMainDom();
var runtimeState = new RuntimeState(logger, null, null, new Lazy(() => mainDom), new Lazy(() => factory.GetInstance()));
@@ -249,7 +250,8 @@ namespace Umbraco.Tests.Runtimes
var profilingLogger = new ProfilingLogger(logger, profiler);
var appCaches = AppCaches.Disabled;
var databaseFactory = Mock.Of();
- var typeLoader = new TypeLoader(appCaches.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
+ var typeFinder = new TypeFinder(Mock.Of());
+ var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
var runtimeState = Mock.Of();
Mock.Get(runtimeState).Setup(x => x.Level).Returns(RuntimeLevel.Run);
var mainDom = Mock.Of();
diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
index f62effcb62..a2f08604b5 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs
@@ -37,7 +37,8 @@ namespace Umbraco.Tests.TestHelpers
var container = RegisterFactory.Create();
var logger = new ProfilingLogger(Mock.Of(), Mock.Of());
- var typeLoader = new TypeLoader(NoAppCache.Instance,
+ var typeFinder = new TypeFinder(Mock.Of());
+ var typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance,
IOHelper.MapPath("~/App_Data/TEMP"),
logger,
false);
diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
index e27fe17bbe..273f7a996e 100644
--- a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
+++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
@@ -5,6 +5,7 @@ using System.Reflection;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
+using Moq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Composing;
@@ -38,7 +39,8 @@ namespace Umbraco.Tests.TestHelpers.Stubs
{
if (_factory != null) return _factory(requestContext);
- var types = TypeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() });
+ var typeFinder = new TypeFinder(Mock.Of());
+ var types = typeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() });
var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));
var t = controllerTypes.SingleOrDefault();
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index b9fd0f6640..4a911680ab 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -288,7 +288,8 @@ namespace Umbraco.Tests.Testing
// common to all tests = cannot be overriden
private static TypeLoader CreateCommonTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
{
- return new TypeLoader(runtimeCache, globalSettings.LocalTempPath, logger, false)
+ var typeFinder = new TypeFinder(Mock.Of());
+ return new TypeLoader(typeFinder, runtimeCache, globalSettings.LocalTempPath, logger, false)
{
AssembliesToScan = new[]
{
diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs
index 3a5405548b..907c5efdd2 100644
--- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs
+++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs
@@ -39,8 +39,9 @@ namespace Umbraco.Tests.Web
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
var factory = new Mock();
+ var typeFinder = new TypeFinder(Mock.Of());
factory.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns(
- new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of())));
+ new TypeLoader(typeFinder, NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of(), Mock.Of())));
factory.Setup(x => x.GetInstance(typeof (ServiceContext))).Returns(serviceContext);
var settings = SettingsForTests.GetDefaultUmbracoSettings();
diff --git a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
index 26d85f60cf..c1147ed5a7 100644
--- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
+++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs
@@ -260,10 +260,11 @@ namespace Umbraco.Tests.Web
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
var container = new Mock();
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
-
+ var typeFinder = new TypeFinder(Mock.Of());
container
.Setup(x => x.GetInstance(typeof(TypeLoader)))
.Returns(new TypeLoader(
+ typeFinder,
NoAppCache.Instance,
IOHelper.MapPath("~/App_Data/TEMP"),
new ProfilingLogger(Mock.Of(), Mock.Of())
diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs
index 7113abd6eb..aa8f735cf2 100644
--- a/src/Umbraco.Web/Editors/EntityController.cs
+++ b/src/Umbraco.Web/Editors/EntityController.cs
@@ -486,6 +486,7 @@ namespace Umbraco.Web.Editors
///
///
///
+ ///
///
public PagedResult GetPagedChildren(
string id,