Creates ITypeFinder interface and simplifies type finder with TypeFinderExtensions, moves GetTypeByName to TypeHelper using assembly name parsing instead of scanning every assembly.
This commit is contained in:
50
src/Umbraco.Core/Composing/ITypeFinder.cs
Normal file
50
src/Umbraco.Core/Composing/ITypeFinder.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
public interface ITypeFinder
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies that Umbraco should scan for type finding
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
IEnumerable<Assembly> AssembliesToScan { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="attributeType"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesOfTypeWithAttribute(
|
||||
Type assignTypeFrom,
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
public class TypeFinder : ITypeFinder
|
||||
{
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private static readonly object LocalFilteredAssemblyCacheLocker = new object();
|
||||
private static readonly List<string> NotifiedLoadExceptionAssemblies = new List<string>();
|
||||
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<Assembly>>(() =>
|
||||
{
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = IOHelper.IsHosted;
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
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<Assembly>();
|
||||
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<HashSet<Assembly>> _allAssemblies;
|
||||
private volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private readonly object _localFilteredAssemblyCacheLocker = new object();
|
||||
private readonly List<string> _notifiedLoadExceptionAssemblies = new List<string>();
|
||||
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
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetAllAssemblies()
|
||||
private IEnumerable<Assembly> GetAllAssemblies()
|
||||
{
|
||||
return AllAssemblies.Value;
|
||||
return _allAssemblies.Value;
|
||||
}
|
||||
|
||||
//Lazy access to the all assemblies list
|
||||
private static readonly Lazy<HashSet<Assembly>> AllAssemblies = new Lazy<HashSet<Assembly>>(() =>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Assembly> AssembliesToScan
|
||||
{
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
get
|
||||
{
|
||||
var isHosted = IOHelper.IsHosted;
|
||||
|
||||
try
|
||||
lock (_localFilteredAssemblyCacheLocker)
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
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<Assembly>();
|
||||
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;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
if (_localFilteredAssemblyCache != null)
|
||||
var assemblies = GetFilteredAssemblies(null, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +186,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
private IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> 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"
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = {
|
||||
private static readonly string[] KnownAssemblyExclusionFilter = {
|
||||
"Antlr3.",
|
||||
"AutoMapper,",
|
||||
"AutoMapper.",
|
||||
@@ -261,115 +259,40 @@ namespace Umbraco.Core.Composing
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="attributeType"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
public IEnumerable<Type> FindClassesOfTypeWithAttribute(
|
||||
Type assignTypeFrom,
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(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());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> 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<TAttribute>(false).Any());
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException(nameof(assemblies));
|
||||
|
||||
return GetClassesWithBaseType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
@@ -377,40 +300,19 @@ namespace Umbraco.Core.Composing
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
public IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
return GetClassesWithAttribute(attributeType, assemblies, onlyConcreteClasses);
|
||||
}
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static IEnumerable<Type> GetClassesWithAttribute(
|
||||
private IEnumerable<Type> GetClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> 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
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClassesWithBaseType(
|
||||
private IEnumerable<Type> GetClassesWithBaseType(
|
||||
Type baseType,
|
||||
IEnumerable<Assembly> 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<Type> GetTypesWithFormattedException(Assembly a)
|
||||
private IEnumerable<Type> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
src/Umbraco.Core/Composing/TypeFinderExtensions.cs
Normal file
45
src/Umbraco.Core/Composing/TypeFinderExtensions.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
public static class TypeFinderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
where TAttribute : Attribute
|
||||
=> typeFinder.FindClassesOfTypeWithAttribute(typeof(T), typeof(TAttribute), assemblies, onlyConcreteClasses);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
=> typeFinder.FindClassesOfType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
where T : Attribute
|
||||
=> typeFinder.FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Composing
|
||||
/// Provides methods to find and instantiate types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This class should be used to get all types, the <see cref="TypeFinder"/> class should never be used directly.</para>
|
||||
/// <para>This class should be used to get all types, the <see cref="Composing.TypeFinder"/> class should never be used directly.</para>
|
||||
/// <para>In most cases this class is not used directly but through extension methods that retrieve specific types.</para>
|
||||
/// <para>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.</para>
|
||||
@@ -48,22 +48,25 @@ namespace Umbraco.Core.Composing
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="runtimeCache">The application runtime cache.</param>
|
||||
/// <param name="localTempPath">Files storage location.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
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)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="runtimeCache">The application runtime cache.</param>
|
||||
/// <param name="localTempPath">Files storage location.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
/// <param name="detectChanges">Whether to detect changes using hashes.</param>
|
||||
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()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the underlying <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
public ITypeFinder TypeFinder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the set of assemblies to scan.
|
||||
/// </summary>
|
||||
@@ -117,7 +126,7 @@ namespace Umbraco.Core.Composing
|
||||
// internal for tests
|
||||
internal IEnumerable<Assembly> AssembliesToScan
|
||||
{
|
||||
get => _assemblies ?? (_assemblies = TypeFinder.GetAssembliesWithKnownExclusions());
|
||||
get => _assemblies ?? (_assemblies = TypeFinder.AssembliesToScan);
|
||||
set => _assemblies = value;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user