如何遍历当前加载的程序集? [英] How do you loop through currently loaded assemblies?

查看:41
本文介绍了如何遍历当前加载的程序集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 ASP.NET 应用程序中有一个诊断"页面,它执行诸如验证数据库连接、显示当前 appSettings 和 ConnectionStrings 等操作.此页面的一部分显示重要的程序集版本类型,但我不知道如何有效地显示所有加载的程序集的版本.

I've got a "diagnostics" page in my ASP.NET application which does things like verify the database connection(s), display the current appSettings and ConnectionStrings, etc. A section of this page displays the Assembly versions of important types used throughout, but I could not figure out how to effectively show the versions of ALL of the loaded assemblies.

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

What is the most effective way to figure out all currently referenced and/or loaded Assemblies in a .NET application?

注意:我对基于文件的方法不感兴趣,比如在特定目录中遍历 *.dll.我对应用程序现在实际使用的内容感兴趣.

Note: I'm not interested in file-based methods, like iterating through *.dll in a particular directory. I am interested in what the application is actually using right now.

推荐答案

此扩展方法以递归方式获取所有引用的程序集,包括嵌套程序集.

This extension method gets all referenced assemblies, recursively, including nested assemblies.

因为它使用 ReflectionOnlyLoad,所以它在一个单独的 AppDomain 中加载程序集,这具有不干扰 JIT 过程的优点.

As it uses ReflectionOnlyLoad, it loads the assemblies in a separate AppDomain, which has the advantage of not interfering with the JIT process.

您会注意到还有一个 MyGetMissingAssembliesRecursive.您可以使用它来检测任何被引用但由于某种原因不在当前目录中的缺失程序集.这在使用 MEF 时非常有用.返回列表将为您提供丢失的程序集以及拥有它的人(其父级).

You'll notice that there is also a MyGetMissingAssembliesRecursive. You can use this to detect any missing assemblies that are referenced, but not present in the current directory for some reason. This is incredibly useful when using MEF. The return list will give you both the missing assembly, and who owns it (its parent).

/// <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.默认情况下,它当前不是线程安全的,因为它引用了一个共享的静态全局变量来发挥它的魔力.

Update

To make this code thread safe, put a lock around it. It's not currently thread safe by default, as it references a shared static global variable to do its magic.

这篇关于如何遍历当前加载的程序集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆