/// <summary> /// Gets an assembly by its AssemblyName.Name /// </summary> /// <param name="Name">The AssemblyName.Name</param> /// <returns>The matching Assembly</returns> public static Assembly GetAssemblyByName(string Name) { if (!AssembliesByName.TryGetValue(Name, out Assembly a)) { a = AppDomain.CurrentDomain.GetAssemblies().First(aa => aa.GetName().Name == Name); AssembliesByName.TryAdd(Name, a); } return(a); }
/// <summary> /// Since everything is cached, we need to make sure ALL potential assemblies are loaded or we might end up missing classes because /// the assembly hasn't been loaded yet. Consider only loading whitelisted references if this is slow /// </summary> static TypeFactory() { StaticLogger.Log($"Penguin.Reflection: {Assembly.GetExecutingAssembly().GetName().Version}", StaticLogger.LoggingLevel.Call); List <string> failedCache = LoadFailedCache(); List <string> blacklist; if (!TypeFactoryGlobalSettings.DisableFailedLoadSkip) { blacklist = LoadBlacklistCache(); } else { blacklist = new List <string>(); } Dictionary <string, Assembly> loadedPaths = new Dictionary <string, Assembly>(); //Map out the loaded assemblies so we can find them by path foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { if (!a.IsDynamic) { if (!loadedPaths.ContainsKey(a.Location)) { loadedPaths.Add(a.Location, a); } } } List <string> referencedPaths = new List <string>(); List <string> searchPaths = new List <string>() { AppDomain.CurrentDomain.BaseDirectory }; if (AppDomain.CurrentDomain.RelativeSearchPath != null) { searchPaths.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.RelativeSearchPath)); } //We're going to add the paths to the loaded assemblies here so we can double //back and ensure we're building the dependencies for the loaded assemblies that //do NOT reside in the EXE/Bin directories HashSet <string> SearchedPaths = new HashSet <string>(); foreach (string searchPath in searchPaths) { StaticLogger.Log($"RE: Dynamically loading assemblys from {searchPath}", StaticLogger.LoggingLevel.Call); referencedPaths.AddRange(Directory.GetFiles(searchPath, "*.dll")); referencedPaths.AddRange(Directory.GetFiles(searchPath, "*.exe")); foreach (string loadPath in referencedPaths) { SearchedPaths.Add(loadPath); //If we're not already loaded if (!loadedPaths.TryGetValue(loadPath, out Assembly a)) { if (failedCache.Contains(loadPath)) { StaticLogger.Log($"RE: Skipping due {FAILED_CACHE}: {loadPath}", StaticLogger.LoggingLevel.Call); continue; } //Check for blacklist string matchingLine = blacklist.FirstOrDefault(b => Regex.IsMatch(Path.GetFileName(loadPath), b)); if (!string.IsNullOrWhiteSpace(matchingLine)) { StaticLogger.Log($"RE: Skipping assembly due to blacklist match ({matchingLine}) {loadPath}", StaticLogger.LoggingLevel.Call); continue; } StaticLogger.Log($"RE: Dynamically loading assembly {loadPath}", StaticLogger.LoggingLevel.Call); try { AssemblyName an = AssemblyName.GetAssemblyName(loadPath); a = LoadAssembly(loadPath, an, true); AssembliesByName.TryAdd(an.Name, a); } catch (Exception ex) { StaticLogger.Log(ex.Message, StaticLogger.LoggingLevel.Call); StaticLogger.Log(ex.StackTrace, StaticLogger.LoggingLevel.Call); failedCache.Add(loadPath); } } if (!(a is null)) { AddReferenceInformation(a); } } } //And now we double check to make sure we're not missing anything in the loaded //assemblies that were not found in our path discovery foreach (KeyValuePair <string, Assembly> kvp in loadedPaths) { if (!SearchedPaths.Contains(kvp.Key)) { AddReferenceInformation(kvp.Value); } } StaticLogger.Log($"RE: {nameof(TypeFactory)} static initialization completed", StaticLogger.LoggingLevel.Final); try { AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; List <Assembly> CurrentlyLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); foreach (Assembly assembly in CurrentlyLoadedAssemblies) { if (!assembly.IsDynamic) { CheckLoadingPath(assembly.Location); } } } catch (SecurityException ex) { StaticLogger.Log($"RE: A security exception was thrown attempting to subscribe to assembly load events: {ex.Message}", StaticLogger.LoggingLevel.Final); } if (!TypeFactoryGlobalSettings.DisableFailedLoadSkip) { File.WriteAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FAILED_CACHE), failedCache); } }