diff --git a/umbraco/businesslogic/Utils/TypeFinder.cs b/umbraco/businesslogic/Utils/TypeFinder.cs index 17370cfbbe..360af76580 100644 --- a/umbraco/businesslogic/Utils/TypeFinder.cs +++ b/umbraco/businesslogic/Utils/TypeFinder.cs @@ -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 /// public static class TypeFinder { + // zb-00044 #29989 : refactor FindClassesMarkedWithAttribute /// /// Searches all loaded assemblies for classes marked with the attribute passed in. @@ -22,53 +24,51 @@ namespace umbraco.BusinessLogic.Utils public static List FindClassesMarkedWithAttribute(Type attribute) { List types = new List(); - - - - 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 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; + } + } + } + /// /// Searches all loaded assemblies for classes of the type passed in. /// @@ -171,6 +171,5 @@ namespace umbraco.BusinessLogic.Utils { return t => (type.IsAssignableFrom(t) && (onlyConcreteClasses ? (t.IsClass && !t.IsAbstract) : true)); } - } } diff --git a/umbraco/businesslogic/Utils/TypeResolver.cs b/umbraco/businesslogic/Utils/TypeResolver.cs index 55b7dc5930..584ae1bb76 100644 --- a/umbraco/businesslogic/Utils/TypeResolver.cs +++ b/umbraco/businesslogic/Utils/TypeResolver.cs @@ -145,5 +145,69 @@ namespace umbraco.BusinessLogic.Utils return result.ToArray(); } - } + + // zb-00044 #29989 : helper method to help injecting services (poor man's ioc) + /// + /// Creates an instance of the type indicated by and ensures + /// it implements the interface indicated by . + /// + /// The type of the service interface. + /// The name of the service we're trying to implement. + /// The full name of the type implementing the service. + /// A class implementing . + public static T CreateInstance(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; + } + + } }