fix #29989 - refactor TypeFinder and TypeResolver

This commit is contained in:
sgay
2011-02-01 13:17:49 -01:00
parent 7631522a9e
commit 39a34954ce
2 changed files with 98 additions and 35 deletions

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}
}