Jak pętlować aktualnie załadowane zespoły?

Mam stronę "diagnostyka" w moim ASP.NET aplikacja, która sprawdza połączenia z bazą danych, wyświetla bieżące ustawienia aplikacji i ConnectionStrings, itp. Sekcja tej strony wyświetla wersje złożeń ważnych typów używanych w całym okresie, ale nie mogłem dowiedzieć się, jak skutecznie pokazać wersje wszystkich załadowanych złożeń.

Jaki jest najskuteczniejszy sposób na sprawdzenie wszystkich aktualnie odwołanych i / lub załadowanych zestawów w Aplikacja. NET?

Uwaga: nie interesują mnie metody oparte na plikach, takie jak iteracja przez *.dll w określonym katalogu. Jestem teraz zainteresowany tym, czym właściwie jest aplikacja za pomocą .

Author: starblue, 2008-12-20

2 answers

Ta metoda rozszerzenia pobiera rekurencyjnie wszystkie odwołujące się zespoły, łącznie z zagnieżdżonymi.

Ponieważ używa ReflectionOnlyLoad, ładuje zespoły w oddzielnej AppDomain, która ma tę zaletę, że nie ingeruje w proces JIT.

Zauważysz, że istnieje również MyGetMissingAssembliesRecursive. Można tego użyć do wykrycia brakujących zestawów, do których się odwołuje, ale z jakiegoś powodu nie ma ich w bieżącym katalogu. Jest to niezwykle przydatne przy użyciu MEF . Lista zwrotów poda ci zarówno brakujące zgromadzenie, jak i kto jest jego właścicielem (jego rodzicem).

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

Update

Aby ten wątek kodu był bezpieczny, umieść lock wokół niego. Obecnie nie jest on domyślnie bezpieczny dla wątku, ponieważ odwołuje się do współdzielonej statycznej zmiennej globalnej, aby zrobić to magicznie.

 17
Author: Contango,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-12 21:35:50

Pobieranie wczytanych zestawów dla bieżącego AppDomain:

var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

Uzyskiwanie zestawów, do których odwołuje się inny zestaw:

var referencedAssemblies = someAssembly.GetReferencedAssemblies();

Zauważ, że jeśli assembly a odwołuje się do assembly B i assembly A jest załadowany, to nie oznacza, że assembly B jest również załadowany. Montaż B zostanie załadowany tylko wtedy, gdy jest to potrzebne. Z tego powodu GetReferencedAssemblies() zwraca instancje AssemblyName zamiast instancji Assembly.

 183
Author: Kent Boogaart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 14:53:33