你如何循环通过当前加载的程序集?

我在ASP.NET应用程序中有一个“诊断”页面,它可以执行诸如validation数据库连接,显示当前的appSettings和ConnectionStrings等。此页面的一部分显示了整个使用的重要types的程序集版本,但我想不出如何有效地显示所有加载的程序集的版本。

在.NET应用程序中找出所有当前引用和/或加载的程序集的最有效方法是什么?

注意:我对基于文件的方法不感兴趣,例如在特定目录中遍历* .dll。 我感兴趣的是现在应用程序正在使用什么。

此扩展方法recursion获取所有引用的程序集,包括嵌套程序集。

由于它使用ReflectionOnlyLoad ,因此它将程序集加载到单独的AppDomain中,这具有不干扰JIT进程的优点。

你会注意到还有一个MyGetMissingAssembliesRecursive 。 您可以使用它来检测所引用的任何缺less的程序集,但由于某些原因,它们不会出现在当前目录中。 这在使用MEF时非常有用。 退货清单将给你两个缺less的程序集,以及谁拥有它(它的父母)。

 /// <summary> /// Intent: Get referenced assemblies, either recursively or flat. Not thread safe, if running in a multi /// threaded environment must use locks. /// </summary> public static class GetReferencedAssemblies { static void Demo() { var referencedAssemblies = Assembly.GetEntryAssembly().MyGetReferencedAssembliesRecursive(); var missingAssemblies = Assembly.GetEntryAssembly().MyGetMissingAssembliesRecursive(); // Can use this within a class. //var referencedAssemblies = this.MyGetReferencedAssembliesRecursive(); } public class MissingAssembly { public MissingAssembly(string missingAssemblyName, string missingAssemblyNameParent) { MissingAssemblyName = missingAssemblyName; MissingAssemblyNameParent = missingAssemblyNameParent; } public string MissingAssemblyName { get; set; } public string MissingAssemblyNameParent { get; set; } } private static Dictionary<string, Assembly> _dependentAssemblyList; private static List<MissingAssembly> _missingAssemblyList; /// <summary> /// Intent: Get assemblies referenced by entry assembly. Not recursive. /// </summary> public static List<string> MyGetReferencedAssembliesFlat(this Type type) { var results = type.Assembly.GetReferencedAssemblies(); return results.Select(o => o.FullName).OrderBy(o => o).ToList(); } /// <summary> /// Intent: Get assemblies currently dependent on entry assembly. Recursive. /// </summary> public static Dictionary<string, Assembly> MyGetReferencedAssembliesRecursive(this Assembly assembly) { _dependentAssemblyList = new Dictionary<string, Assembly>(); _missingAssemblyList = new List<MissingAssembly>(); InternalGetDependentAssembliesRecursive(assembly); // Only include assemblies that we wrote ourselves (ignore ones from GAC). var keysToRemove = _dependentAssemblyList.Values.Where( o => o.GlobalAssemblyCache == true).ToList(); foreach (var k in keysToRemove) { _dependentAssemblyList.Remove(k.FullName.MyToName()); } return _dependentAssemblyList; } /// <summary> /// Intent: Get missing assemblies. /// </summary> public static List<MissingAssembly> MyGetMissingAssembliesRecursive(this Assembly assembly) { _dependentAssemblyList = new Dictionary<string, Assembly>(); _missingAssemblyList = new List<MissingAssembly>(); InternalGetDependentAssembliesRecursive(assembly); return _missingAssemblyList; } /// <summary> /// Intent: Internal recursive class to get all dependent assemblies, and all dependent assemblies of /// dependent assemblies, etc. /// </summary> private static void InternalGetDependentAssembliesRecursive(Assembly assembly) { // Load assemblies with newest versions first. Omitting the ordering results in false positives on // _missingAssemblyList. var referencedAssemblies = assembly.GetReferencedAssemblies() .OrderByDescending(o => o.Version); foreach (var r in referencedAssemblies) { if (String.IsNullOrEmpty(assembly.FullName)) { continue; } if (_dependentAssemblyList.ContainsKey(r.FullName.MyToName()) == false) { try { var a = Assembly.ReflectionOnlyLoad(r.FullName); _dependentAssemblyList[a.FullName.MyToName()] = a; InternalGetDependentAssembliesRecursive(a); } catch (Exception ex) { _missingAssemblyList.Add(new MissingAssembly(r.FullName.Split(',')[0], assembly.FullName.MyToName())); } } } } private static string MyToName(this string fullName) { return fullName.Split(',')[0]; } } 

更新

为了使这个代码线程安全,请lock它。 目前它不是线程安全的,因为它引用了一个共享的静态全局variables来发挥它的魔力。

获取当前AppDomain加载程序集:

 var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 

获取另一个程序集引用的程序集:

 var referencedAssemblies = someAssembly.GetReferencedAssemblies(); 

请注意,如果程序集A引用程序集B和程序集A已加载,那并不意味着程序集B也被加载。 assemblyB将只在需要的时候加载。 因此, GetReferencedAssemblies()将返回AssemblyName实例而不是Assembly实例。