This commit is contained in:
Shannon Deminick
2013-04-29 19:57:44 -10:00

View File

@@ -2,23 +2,18 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Compilation;
using System.Web.Hosting;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
namespace Umbraco.Core
{
//TODO: Get the App_Code stuff in here from the old one
/// <summary>
@@ -27,7 +22,6 @@ namespace Umbraco.Core
/// </summary>
public static class TypeFinder
{
private static readonly ConcurrentBag<Assembly> LocalFilteredAssemblyCache = new ConcurrentBag<Assembly>();
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
private static ReadOnlyCollection<Assembly> _allAssemblies = null;
@@ -86,8 +80,7 @@ namespace Umbraco.Core
}
//now set the _allAssemblies
_allAssemblies = new ReadOnlyCollection<Assembly>(assemblies);
_allAssemblies = new ReadOnlyCollection<Assembly>(assemblies);
}
catch (InvalidOperationException e)
{
@@ -100,8 +93,8 @@ namespace Umbraco.Core
}
return _allAssemblies;
}
}
/// <summary>
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
/// </summary>
@@ -111,7 +104,6 @@ namespace Umbraco.Core
/// </remarks>
internal static IEnumerable<Assembly> GetBinAssemblies()
{
if (_binFolderAssemblies == null)
{
using (new WriteLock(Locker))
@@ -143,7 +135,8 @@ namespace Umbraco.Core
{
try
{
var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
var foundAssembly =
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
if (foundAssembly != null)
{
binFolderAssemblies.Add(foundAssembly);
@@ -162,7 +155,7 @@ namespace Umbraco.Core
}
}
return _binFolderAssemblies;
}
}
/// <summary>
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
@@ -181,7 +174,7 @@ namespace Umbraco.Core
assemblies.ForEach(LocalFilteredAssemblyCache.Add);
}
return LocalFilteredAssemblyCache;
}
}
/// <summary>
/// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
@@ -190,18 +183,18 @@ namespace Umbraco.Core
/// <param name="exclusionFilter"></param>
/// <returns></returns>
private static IEnumerable<Assembly> GetFilteredAssemblies(
IEnumerable<Assembly> excludeFromResults = null,
IEnumerable<Assembly> excludeFromResults = null,
string[] exclusionFilter = null)
{
if (excludeFromResults == null)
excludeFromResults = new List<Assembly>();
if (exclusionFilter == null)
exclusionFilter = new string[] { };
exclusionFilter = new string[] {};
return GetAllAssemblies()
.Where(x => !excludeFromResults.Contains(x)
&& !x.GlobalAssemblyCache
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
&& !x.GlobalAssemblyCache
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
}
/// <summary>
@@ -211,42 +204,42 @@ namespace Umbraco.Core
/// 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
/// </remarks>
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
{
"mscorlib,",
"System.",
"Antlr3.",
"Autofac.",
"Autofac,",
"Castle.",
"ClientDependency.",
"DataAnnotationsExtensions.",
"DataAnnotationsExtensions,",
"Dynamic,",
"HtmlDiff,",
"Iesi.Collections,",
"log4net,",
"Microsoft.",
"Newtonsoft.",
"NHibernate.",
"NHibernate,",
"NuGet.",
"RouteDebugger,",
"SqlCE4Umbraco,",
"umbraco.datalayer,",
"umbraco.interfaces,",
"umbraco.providers,",
"Umbraco.Web.UI,",
"umbraco.webservices",
"Lucene.",
"Examine,",
"Examine.",
"ServiceStack.",
"MySql.",
"HtmlAgilityPack.",
"TidyNet.",
"ICSharpCode.",
"CookComputing."
};
{
"mscorlib,",
"System.",
"Antlr3.",
"Autofac.",
"Autofac,",
"Castle.",
"ClientDependency.",
"DataAnnotationsExtensions.",
"DataAnnotationsExtensions,",
"Dynamic,",
"HtmlDiff,",
"Iesi.Collections,",
"log4net,",
"Microsoft.",
"Newtonsoft.",
"NHibernate.",
"NHibernate,",
"NuGet.",
"RouteDebugger,",
"SqlCE4Umbraco,",
"umbraco.datalayer,",
"umbraco.interfaces,",
"umbraco.providers,",
"Umbraco.Web.UI,",
"umbraco.webservices",
"Lucene.",
"Examine,",
"Examine.",
"ServiceStack.",
"MySql.",
"HtmlAgilityPack.",
"TidyNet.",
"ICSharpCode.",
"CookComputing."
};
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
where TAttribute : Attribute
@@ -260,13 +253,19 @@ namespace Umbraco.Core
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
}
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies,
bool onlyConcreteClasses)
where TAttribute : Attribute
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
// a assembly cant contain types that are assignable to a type it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (T), assemblies);
// a assembly cant contain types with a attribute it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (TAttribute), assemblies);
var l = new List<Type>();
foreach(var a in assemblies)
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface
@@ -325,7 +324,7 @@ namespace Umbraco.Core
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
where T : Attribute
{
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
return FindClassesWithAttribute(typeof (T), assemblies, onlyConcreteClasses);
}
/// <summary>
@@ -335,23 +334,58 @@ namespace Umbraco.Core
/// <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(Type type, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
public static IEnumerable<Type> FindClassesWithAttribute(Type type, IEnumerable<Assembly> assemblies,
bool onlyConcreteClasses)
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
if (!TypeHelper.IsTypeAssignableFrom<Attribute>(type))
throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
// a assembly cant contain types with a attribute it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(type, assemblies);
var l = new List<Type>();
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;
where
!t.IsInterface && t.GetCustomAttributes(type, false).Any() &&
(!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
}
/// <summary>
/// Removes assemblies that doesn't reference the assembly of the type we are looking for.
/// </summary>
/// <param name="type"></param>
/// <param name="assemblies"></param>
/// <returns></returns>
private static IEnumerable<Assembly> RemoveAssembliesThatDontReferenceAssemblyOfType(Type type,
IEnumerable<Assembly> assemblies)
{
// Avoid scanning assembly if it doesn't contain a reference to the assembly containing the type we are looking for
// to the assembly containing the attribute we are looking for
var assemblyNameOfType = type.Assembly.GetName().Name;
return assemblies
.Where(assembly => assembly == type.Assembly
|| HasReferenceToAssemblyWithName(assembly, assemblyNameOfType)).ToList();
}
/// <summary>
/// checks if the assembly has a reference with the same name as the expected assembly name.
/// </summary>
/// <param name="assembly"></param>
/// <param name="expectedAssemblyName"></param>
/// <returns></returns>
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
{
return assembly
.GetReferencedAssemblies()
.Select(a => a.Name)
.Contains(expectedAssemblyName, StringComparer.Ordinal);
}
/// <summary>
/// Finds the classes with attribute.
@@ -376,9 +410,8 @@ namespace Umbraco.Core
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
}
#region Private methods
/// <summary>
/// Gets a collection of assignables of type T from a collection of assemblies
/// </summary>
@@ -388,20 +421,26 @@ namespace Umbraco.Core
/// <returns></returns>
private static IEnumerable<Type> GetAssignablesFromType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
return GetTypes(typeof(T), assemblies, onlyConcreteClasses);
return GetTypes(typeof (T), assemblies, onlyConcreteClasses);
}
private static IEnumerable<Type> GetTypes(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
private static IEnumerable<Type> GetTypes(Type assignTypeFrom, IEnumerable<Assembly> assemblies,
bool onlyConcreteClasses)
{
// a assembly cant contain types that are assignable to a type it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(assignTypeFrom, assemblies);
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
where
!t.IsInterface && assignTypeFrom.IsAssignableFrom(t) &&
(!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
return l;
}
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
@@ -420,15 +459,12 @@ namespace Umbraco.Core
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
{
sb.AppendLine("Exception: " + loaderException.ToString());
sb.AppendLine("Exception: " + loaderException);
}
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
}
}
#endregion
}
}
}