/// <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"> /// An <see cref="IEnumerable{Assembly}"/> to exclude. /// </param> /// <returns>The collection of local assemblies.</returns> internal static HashSet <Assembly> GetAssembliesWithKnownExclusions( IEnumerable <Assembly> excludeFromResults = null) { using (var locker = new UpgradeableReadLock(LocalFilteredAssemblyCacheLocker)) { if (LocalFilteredAssemblyCache.Any()) { return(LocalFilteredAssemblyCache); } locker.UpgradeToWriteLock(); var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter); foreach (var assembly in assemblies) { LocalFilteredAssemblyCache.Add(assembly); } return(LocalFilteredAssemblyCache); } }
/// <summary> /// Lazily loads a reference to all assemblies and only local assemblies. /// This is a modified version of: /// <see href="http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder"/> /// </summary> /// <remarks> /// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been /// loaded in the CLR, not all assemblies. /// See these threads: /// <see href="http://issues.umbraco.org/issue/U5-198"/> /// <see href="http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app"/> /// <see href="http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl"/> /// </remarks> /// <returns> /// The <see cref="HashSet{Assembly}"/>. /// </returns> internal static HashSet <Assembly> GetAllAssemblies() { using (var locker = new UpgradeableReadLock(Locker)) { if (_allAssemblies == null) { locker.UpgradeToWriteLock(); try { // 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 assemblies = new HashSet <Assembly>(); foreach (var file in binAssemblyFiles) { try { var assemblyName = AssemblyName.GetAssemblyName(file); assemblies.Add(Assembly.Load(assemblyName)); } catch (Exception ex) { if (ex is SecurityException || ex is BadImageFormatException || ex is IOException) { // Swallow exception but allow debugging. Debug.WriteLine(ex.Message); } else { throw; } } } // If for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies. if (!assemblies.Any()) { foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { assemblies.Add(assembly); } } // Here we are trying to get the App_Code assembly string[] fileExtensions = { ".cs", ".vb" }; var appCodeFolder = new DirectoryInfo(IOHelper.MapPath("~/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())) { var appCodeAssembly = Assembly.Load("App_Code"); if (!assemblies.Contains(appCodeAssembly)) { assemblies.Add(appCodeAssembly); } } // Now set the allAssemblies _allAssemblies = new HashSet <Assembly>(assemblies); } catch (InvalidOperationException e) { if (!(e.InnerException is SecurityException)) { throw; } _binFolderAssemblies = _allAssemblies; } } return(_allAssemblies); } }