it-swarm.com.de

Wie durchlaufen Sie aktuell geladene Baugruppen?

In meiner ASP.NET-Anwendung befindet sich eine "Diagnoseseite", auf der z. B. die Datenbankverbindung (en) überprüft, die aktuellen appSettings- und ConnectionStrings-Werte angezeigt werden usw. In einem Abschnitt dieser Seite werden die Assembly-Versionen wichtiger Typen angezeigt, die in allen Fällen verwendet werden Ich konnte jedoch nicht herausfinden, wie die Versionen ALLER geladenen Assemblys effektiv angezeigt werden.

Was ist die effektivste Methode, um alle aktuell referenzierten und/oder geladenen Assemblys in einer .NET-Anwendung herauszufinden?

Hinweis: Ich bin nicht an dateibasierten Methoden interessiert, wie das Durchlaufen von * .dll in einem bestimmten Verzeichnis. Ich bin daran interessiert, was die Anwendung aktuell unter Verwendung von ist.

117
Jess Chadwick

Diese Erweiterungsmethode ruft alle referenzierten Assemblys einschließlich verschachtelter Assemblys rekursiv ab.

Da ReflectionOnlyLoad verwendet wird, werden die Assemblys in einer separaten AppDomain geladen, was den Vorteil hat, dass der JIT-Prozess nicht beeinträchtigt wird.

Sie werden feststellen, dass es auch ein MyGetMissingAssembliesRecursive gibt. Sie können dies verwenden, um fehlende Assemblys zu erkennen, auf die verwiesen wird, die jedoch aus irgendeinem Grund nicht im aktuellen Verzeichnis vorhanden sind. Dies ist unglaublich nützlich, wenn Sie MEF verwenden. In der Rückgabeliste sehen Sie sowohl die fehlende Assembly als auch, wem sie gehört (deren übergeordnetes Element).

/// <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];
    }
}

Aktualisieren

Um diesen Code-Thread sicher zu machen, setzen Sie ein lock um ihn herum. Es ist derzeit standardmäßig nicht threadsicher, da es auf eine gemeinsam genutzte statische globale Variable verweist, um seine Magie zu entfalten.

23
Contango

Geladene Assemblys für das aktuelle AppDomain abrufen:

var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

Abrufen der Assemblys, auf die von einer anderen Assembly verwiesen wird:

var referencedAssemblies = someAssembly.GetReferencedAssemblies();

Beachten Sie, dass, wenn Assembly A auf Assembly B verweist und Assembly A geladen wird, dies nicht impliziert, dass Assembly B ebenfalls geladen wird. Die Baugruppe B wird nur geladen, wenn sie benötigt wird. Aus diesem Grund gibt GetReferencedAssemblies() statt AssemblyName Instanzen Assembly Instanzen zurück.

190
Kent Boogaart