fix #29989 - refactor TypeFinder and TypeResolver
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using umbraco.IO;
|
||||
|
||||
namespace umbraco.BusinessLogic.Utils
|
||||
@@ -14,6 +15,7 @@ namespace umbraco.BusinessLogic.Utils
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
// zb-00044 #29989 : refactor FindClassesMarkedWithAttribute
|
||||
|
||||
/// <summary>
|
||||
/// Searches all loaded assemblies for classes marked with the attribute passed in.
|
||||
@@ -22,53 +24,51 @@ namespace umbraco.BusinessLogic.Utils
|
||||
public static List<Type> FindClassesMarkedWithAttribute(Type attribute)
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
|
||||
|
||||
|
||||
|
||||
bool searchGAC = false;
|
||||
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
//don't check any types if the assembly is part of the GAC
|
||||
// skip if the assembly is part of the GAC
|
||||
if (!searchGAC && assembly.GlobalAssemblyCache)
|
||||
continue;
|
||||
|
||||
foreach (Type type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttributes(attribute, true).Length > 0)
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
types.AddRange(FindClassesMarkedWithAttribute(assembly, attribute));
|
||||
}
|
||||
|
||||
// also add types from app_code
|
||||
try
|
||||
|
||||
// also add types from app_code, if any
|
||||
DirectoryInfo appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
if (appCodeFolder.Exists && appCodeFolder.GetFiles().Length > 0)
|
||||
{
|
||||
// only search the App_Code folder if it's not empty
|
||||
DirectoryInfo appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
if (appCodeFolder.GetFiles().Length > 0)
|
||||
{
|
||||
foreach (Type type in System.Reflection.Assembly.Load("App_Code").GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttributes(attribute, true).Length > 0)
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
types.AddRange(FindClassesMarkedWithAttribute(Assembly.Load("App_Code"), attribute));
|
||||
}
|
||||
catch { } // Empty catch - this just means that an App_Code assembly wasn't generated by the files in folder
|
||||
|
||||
|
||||
|
||||
return types;
|
||||
|
||||
}
|
||||
|
||||
static IEnumerable<Type> FindClassesMarkedWithAttribute(Assembly assembly, Type attribute)
|
||||
{
|
||||
try
|
||||
{
|
||||
return assembly.GetTypes().Where(type => type.GetCustomAttributes(attribute, true).Length > 0);
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
if (GlobalSettings.DebugMode)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Unable to load one or more of the types in assembly '{0}'. Exceptions were thrown:", assembly.FullName);
|
||||
foreach (Exception e in ex.LoaderExceptions)
|
||||
sb.AppendFormat("\n{0}: {1}", e.GetType().FullName, e.Message);
|
||||
throw new Exception(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// return the types that were loaded, ignore those that could not be loaded
|
||||
return ex.Types;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all loaded assemblies for classes of the type passed in.
|
||||
/// </summary>
|
||||
@@ -171,6 +171,5 @@ namespace umbraco.BusinessLogic.Utils
|
||||
{
|
||||
return t => (type.IsAssignableFrom(t) && (onlyConcreteClasses ? (t.IsClass && !t.IsAbstract) : true));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,5 +145,69 @@ namespace umbraco.BusinessLogic.Utils
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
// zb-00044 #29989 : helper method to help injecting services (poor man's ioc)
|
||||
/// <summary>
|
||||
/// Creates an instance of the type indicated by <paramref name="fullName"/> and ensures
|
||||
/// it implements the interface indicated by <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service interface.</typeparam>
|
||||
/// <param name="service">The name of the service we're trying to implement.</param>
|
||||
/// <param name="fullName">The full name of the type implementing the service.</param>
|
||||
/// <returns>A class implementing <typeparamref name="T"/>.</returns>
|
||||
public static T CreateInstance<T>(string service, string fullName)
|
||||
where T : class
|
||||
{
|
||||
// try to get the assembly and type names
|
||||
var parts = fullName.Split(',');
|
||||
if (parts.Length != 2)
|
||||
throw new Exception(string.Format("Can not create instance for '{0}': '{1}' is not a valid type full name.", service, fullName));
|
||||
|
||||
string typeName = parts[0];
|
||||
string assemblyName = parts[1];
|
||||
T impl;
|
||||
Assembly assembly;
|
||||
Type type;
|
||||
|
||||
// try to load the assembly
|
||||
try
|
||||
{
|
||||
assembly = Assembly.Load(assemblyName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(string.Format("Can not create instance for '{0}', failed to load assembly '{1}': {2} was thrown ({3}).", service, assemblyName, e.GetType().FullName, e.Message));
|
||||
}
|
||||
|
||||
// try to get the type
|
||||
try
|
||||
{
|
||||
type = assembly.GetType(typeName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(string.Format("Can not create instance for '{0}': failed to get type '{1}' in assembly '{2}': {3} was thrown ({4}).", service, typeName, assemblyName, e.GetType().FullName, e.Message));
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
throw new Exception(string.Format("Can not create instance for '{0}': failed to get type '{1}' in assembly '{2}'.", service, typeName, assemblyName));
|
||||
|
||||
// try to instanciate the type
|
||||
try
|
||||
{
|
||||
impl = Activator.CreateInstance(type) as T;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(string.Format("Can not create instance for '{0}': failed to instanciate: {1} was thrown ({2}).", service, e.GetType().FullName, e.Message));
|
||||
}
|
||||
|
||||
// ensure it implements the requested type
|
||||
if (impl == null)
|
||||
throw new Exception(string.Format("Can not create instance for '{0}': type '{1}' does not implement '{2}'.", service, fullName, typeof(T).FullName));
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user