¿Cómo recorre los ensamblados cargados actualmente?

Tengo una página de “diagnóstico” en mi aplicación ASP.NET que hace cosas como verificar la (s) conexión (es) de la base de datos, mostrar la configuración de la aplicación actual y ConnectionStrings, etc. Una sección de esta página muestra las versiones de ensamblaje de tipos importantes utilizados en todas partes , pero no pude encontrar la manera de mostrar efectivamente las versiones de TODOS los ensamblajes cargados.

¿Cuál es la forma más efectiva de descubrir todos los ensamblados actualmente referenciados y / o cargados en una aplicación .NET?

Nota: No me interesan los métodos basados ​​en archivos, como iterar a través de * .dll en un directorio en particular. Estoy interesado en lo que la aplicación está usando en este momento.

Este método de extensión obtiene todos los ensamblados a los que se hace referencia, recursivamente, incluidos los ensamblajes nesteds.

Como utiliza ReflectionOnlyLoad , carga los ensamblajes en un Dominio de aplicación separado, que tiene la ventaja de no interferir con el proceso JIT.

Notarás que también hay un MyGetMissingAssembliesRecursive . Puede usar esto para detectar cualquier conjunto faltante al que se haga referencia, pero que no esté presente en el directorio actual por algún motivo. Esto es increíblemente útil cuando se usa MEF . La lista de retorno le dará tanto el ensamblaje que falta, y quién lo posee (su padre).

 ///  /// Intent: Get referenced assemblies, either recursively or flat. Not thread safe, if running in a multi /// threaded environment must use locks. ///  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 _dependentAssemblyList; private static List _missingAssemblyList; ///  /// Intent: Get assemblies referenced by entry assembly. Not recursive. ///  public static List MyGetReferencedAssembliesFlat(this Type type) { var results = type.Assembly.GetReferencedAssemblies(); return results.Select(o => o.FullName).OrderBy(o => o).ToList(); } ///  /// Intent: Get assemblies currently dependent on entry assembly. Recursive. ///  public static Dictionary MyGetReferencedAssembliesRecursive(this Assembly assembly) { _dependentAssemblyList = new Dictionary(); _missingAssemblyList = new List(); 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; } ///  /// Intent: Get missing assemblies. ///  public static List MyGetMissingAssembliesRecursive(this Assembly assembly) { _dependentAssemblyList = new Dictionary(); _missingAssemblyList = new List(); InternalGetDependentAssembliesRecursive(assembly); return _missingAssemblyList; } ///  /// Intent: Internal recursive class to get all dependent assemblies, and all dependent assemblies of /// dependent assemblies, etc. ///  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]; } } 

Actualizar

Para hacer que este código sea seguro, ponle un lock . Actualmente no es seguro para subprocesos, ya que hace referencia a una variable global estática compartida para hacer su magia.

Obteniendo ensamblajes cargados para el AppDomain actual:

 var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 

Obtener los ensamblados a los que hace referencia otro ensamblaje:

 var referencedAssemblies = someAssembly.GetReferencedAssemblies(); 

Tenga en cuenta que si el conjunto A hace referencia al conjunto B y al conjunto A, no implica que el conjunto B también esté cargado. El ensamblaje B solo se cargará cuando sea necesario. Por ese motivo, GetReferencedAssemblies() devuelve instancias de AssemblyName lugar de instancias de Assembly .