/// <summary> /// Get a list of all embedded assemblies /// </summary> /// <returns>IEnumerable with a containing the names of the resource and of the assemblie</returns> public IEnumerable <string> EmbeddedAssemblyNames(IEnumerable <Assembly> assembliesToCheck = null) { foreach (var loadedAssembly in assembliesToCheck ?? LoadedAssemblies.Where(pair => !AssembliesToIgnore.IsMatch(pair.Key)).Select(pair => pair.Value).ToList()) { string[] resources; try { resources = Resources.GetCachedManifestResourceNames(loadedAssembly); } catch (Exception ex) { Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name); continue; } foreach (var resource in resources) { var resourceMatch = _assemblyResourceNameRegex.Match(resource); if (resourceMatch.Success) { yield return(resourceMatch.Groups["assembly"].Value); } } } }
/// <summary> /// This is called when a new assembly is loaded, we need to know this /// </summary> /// <param name="sender">object</param> /// <param name="args">AssemblyLoadEventArgs</param> private void AssemblyLoad(object sender, AssemblyLoadEventArgs args) { var loadedAssembly = args.LoadedAssembly; var assemblyName = loadedAssembly.GetName().Name; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Loaded {0}", assemblyName); } LoadedAssemblies[assemblyName] = loadedAssembly; if (!_applicationConfig.ScanForEmbeddedAssemblies) { return; } // Ignore resource checking on certain assemblies if (AssembliesToIgnore.IsMatch(assemblyName)) { return; } string[] resources; try { resources = Resources.GetCachedManifestResourceNames(loadedAssembly); } catch (Exception ex) { Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name); return; } foreach (var resource in resources) { var resourceMatch = _assemblyResourceNameRegex.Match(resource); if (!resourceMatch.Success) { continue; } var embeddedAssemblyName = resourceMatch.Groups["assembly"].Value; if (LoadedAssemblies.ContainsKey(embeddedAssemblyName)) { // Ignoring already loaded assembly, as we cannot unload. continue; } var newAssemblyLocation = new AssemblyLocationInformation(embeddedAssemblyName, loadedAssembly, resource); if (AvailableAssemblies.TryGetValue(embeddedAssemblyName, out var availableAssemblyLocationInformation)) { if (availableAssemblyLocationInformation.FileDate > newAssemblyLocation.FileDate) { continue; } } if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Detected additional assembly {0} in {1}", embeddedAssemblyName, loadedAssembly.GetName().Name); } AvailableAssemblies[embeddedAssemblyName] = newAssemblyLocation; } }
/// <summary> /// Do the one time scan of all the assemblies /// </summary> private void ScanForAssemblies() { var assemblies = new HashSet <AssemblyLocationInformation>(); if (_applicationConfig.ScanForEmbeddedAssemblies) { foreach (var loadedAssembly in LoadedAssemblies.Where(pair => !AssembliesToIgnore.IsMatch(pair.Key)).Select(pair => pair.Value).ToList()) { string[] resources; try { resources = Resources.GetCachedManifestResourceNames(loadedAssembly); } catch (Exception ex) { Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name); continue; } foreach (var resource in resources) { var resourceMatch = _assemblyResourceNameRegex.Match(resource); if (resourceMatch.Success) { assemblies.Add(new AssemblyLocationInformation(resourceMatch.Groups["assembly"].Value, loadedAssembly, resource)); } } } } if (_applicationConfig.UseStrictChecking) { foreach (var applicationConfigScanDirectory in _applicationConfig.ScanDirectories) { if (!Directory.Exists(applicationConfigScanDirectory)) { throw new DirectoryNotFoundException(applicationConfigScanDirectory); } } } foreach (var fileLocation in FileLocations.Scan(_applicationConfig.ScanDirectories, _assemblyFilenameRegex, SearchOption.TopDirectoryOnly)) { assemblies.Add(new AssemblyLocationInformation(fileLocation.Item2.Groups["assembly"].Value, fileLocation.Item1)); } // Reduce step 1) Take from the double assemblies only those which are embedded & on the file system in the probing path foreach (var assemblyGroup in assemblies.GroupBy(information => information.Name).ToList()) { var groupList = assemblyGroup.ToList(); if (groupList.Count <= 1) { continue; } // Remove filesystem assemblies from the list which are not in the AssemblyResolveDirectories var unneededAssemblies = groupList.Where(info => !info.IsEmbedded && !info.IsOnProbingPath).ToList(); if (groupList.Count - unneededAssemblies.Count < 1) { continue; } foreach (var unneededAssemblyInformation in unneededAssemblies) { assemblies.Remove(unneededAssemblyInformation); } } // Reduce step 2) foreach (var assemblyGroup in assemblies.GroupBy(information => information.Name).ToList()) { var groupList = assemblyGroup.ToList(); if (groupList.Count <= 1) { continue; } // Remove assemblies which are older foreach (var unneededAssemblyInformation in groupList.OrderBy(info => info.FileDate).Skip(1).ToList()) { assemblies.Remove(unneededAssemblyInformation); } } // Create the assembly locations foreach (var assemblyLocationInformation in assemblies) { AvailableAssemblies[assemblyLocationInformation.Name] = assemblyLocationInformation; } }