перечисление сборок в GAC

Как я могу перечислить все доступные сборки в GAC на С#?

На самом деле я столкнулся с проблемой с глупым кодом - сборка под названием Telerik.Web.UI.dll упоминается и используется в проекте - эта конкретная DLL отсутствует в папке BIN. И приложение отлично работает на сервере, но на моей машине, очевидно, компилятор выдает ошибку. Бывший разработчик настаивает на том, что его нет в GAC на сервере и «это то, что есть». Теперь мне нужно проверить, зарегистрирована ли эта DLL в GAC или нет.

Помощь будет оценена.

Добрый день;


person effkay    schedule 21.10.2009    source источник
comment
@effkey - вам удалось решить эту проблему?   -  person Kev    schedule 05.02.2010
comment
нет; я не смог; скорее я скачал файлы .dll с торрентов (той же версии), и они сработали. Я до сих пор не понимаю, откуда ASP .NET берет DLLz, если их нет в GAC.   -  person effkay    schedule 06.02.2010


Ответы (8)


Если у вас ограниченный доступ к серверу, это может сработать:

// List of all the different types of GAC folders for both 32bit and 64bit
// environments.
List<string> gacFolders = new List<string>() { 
    "GAC", "GAC_32", "GAC_64", "GAC_MSIL", 
    "NativeImages_v2.0.50727_32", 
    "NativeImages_v2.0.50727_64",
    "NativeImages_v4.0.30319_32",
    "NativeImages_v4.0.30319_64"
};

foreach (string folder in gacFolders)
{
    string path = Path.Combine(
       Environment.ExpandEnvironmentVariables(@"%systemroot%\assembly"), 
       folder);

    if(Directory.Exists(path))
    {
        Response.Write("<hr/>" + folder + "<hr/>");

        string[] assemblyFolders = Directory.GetDirectories(path);
        foreach (string assemblyFolder in assemblyFolders)
        {
            Response.Write(assemblyFolder + "<br/>");
        }
    }
}

В основном он перечисляет необработанные папки GAC. Он работает на общем хостинге DiscountASP, поэтому может работать в вашей среде хостинга.

Его можно украсить, углубившись в папку каждой сборки, чтобы получить номер версии и токен открытого ключа.

person Kev    schedule 21.10.2009

Вам действительно не нужно писать что-то на С#, чтобы узнать, находится ли эта конкретная dll в gac. Вы можете использовать gacutil.exe с / l из командной строки, чтобы просмотреть содержимое GAC.

person Mike Two    schedule 21.10.2009
comment
если бы я мог - у меня ограниченный доступ к серверу - то есть только FTP :) но все же спасибо за комментарий - person effkay; 21.10.2009
comment
@effkay - извините, это не помогло. Если у вас ограниченный доступ к серверу, то как поможет кодовое решение? - person Mike Two; 21.10.2009
comment
@MikeTwo Похоже, он планирует загрузить веб-страницу со списком сборок, находящихся в GAC. - person BrainSlugs83; 17.02.2012

Прочтите эту статью codeproject GAC API. Это использует недокументированную fusion.dll для перечисления GAC. Но автор утверждает, что

Известно, что этот код работает с .NET 1.1 и 2.0. Обратите внимание, что DLL fusion.dll отличается в версиях 1.1 и 2.0. Поэтому, если у вас установлены оба фреймворка, убедитесь, что код указывает на правильную DLL. В противном случае большинство вызовов API завершится ошибкой. Реализация по умолчанию использует тот, который находится в каталоге WINDOWS.

person RameshVel    schedule 21.10.2009
comment
спасибо - проверю; но я боюсь, что это может создать проблему с разрешениями; так как у меня ограниченный доступ к серверу - и я сомневаюсь в его функциональности под пользователем ASP NET. но все равно спасибо; Я тоже видел это раньше, но исключил из-за вышеперечисленных сомнений. Но дай мне попробовать. - person effkay; 21.10.2009
comment
Это не бездокументарно. По крайней мере, не больше. support.microsoft.com/kb/317540 или msdn.microsoft.com/en-us/library/ms404523.aspx - person Lars Truijens; 01.05.2014

Если это простой сайт ASP.NET, а сборка не находится ни в папке bin сайта, ни в GAC сервера (и в web.config нет ничего подозрительного), возможно, сайт является каким-то дочерним сайтом и один из вышестоящих сайтов содержит ссылку в папке bin (или что-то подозрительное в его web.config, поскольку подсайты/папки наследуют web.configs своих родителей)?

Теперь, если у вас есть среда, в которой файл загружается правильно (и похоже, что вы это делаете), вы можете просто спросить .NET, откуда берется .dll, и вместо этого отобразить это, например:

Assembly a = Assembly.Load("Microsoft.VisualStudio.Shell, Version=2.0.0.0, "
           + "PublicKeyToken=b03f5f7f11d50a3a, Culture=Neutral");

Console.WriteLine(a.Location);

Загрузит сборку и отобразит ее местоположение на диске, мой вывод: C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Shell\2.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Shell.dll

Если он находится в папке «C:\Windows\assembly\», вы знаете, что он находится в GAC.

Вы также можете сделать это без вызова Assembly.Load, если вы уже ссылаетесь на сборку, вы можете перечислить сборки, загруженные в текущий app.domain, и просто распечатать (или отобразить в буквальном элементе управления или Response.Write и т. д.). ) каковы их свойства .Location.

Редактировать. Код для этого выглядит примерно так:

foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
    Console.WriteLine(a.GetName().FullName);
    Console.WriteLine(a.Location);
    Console.WriteLine();
}

Редактировать. В среде с полным доверием следующий код (консольное приложение) будет перечислять GAC и записывать каждую сборку. Его легко преобразовать в приложение ASP.NET, но я не уверен, что это будет работать в среде, которая не соответствует полному доверию (просто предполагаю, что вам может повезти):

static void ProcessFile(string file)
{
    try
    {
        Assembly a = Assembly.LoadFile(file);

        Console.WriteLine(a.GetName().FullName);
    }
    catch { /* do nothing */ }
}

static void ProcessFolder(string folder)
{
    foreach (string file in Directory.GetFiles(folder))
    {
        ProcessFile(file);
    }

    foreach (string subFolder in Directory.GetDirectories(folder))
    {
        ProcessFolder(subFolder);
    }
}

static void Main(string[] args)
{
    ProcessFolder(@"C:\Windows\Assembly");
}
person BrainSlugs83    schedule 17.02.2012

простой способ перечисления файлов dll в каталоге

public static string[] GetGlobalAssemblyCacheFiles(string path)
{
    List<string> files = new List<string>();

    DirectoryInfo di = new DirectoryInfo(path);

    foreach (FileInfo fi in di.GetFiles("*.dll"))
    {
        files.Add(fi.FullName);
    }

    foreach (DirectoryInfo diChild in di.GetDirectories())
    {
        var files2 = GetGlobalAssemblyCacheFiles(diChild.FullName);
        files.AddRange(files2);
    }

    return files.ToArray();
}

и вы можете получить все файлы

string gacPath = Environment.GetFolderPath(System.Environment.SpecialFolder.Windows) + "\\assembly";
var files = GetGlobalAssemblyCacheFiles(gacPath);

Если вам нужно загрузить каждую сборку, вы получите исключение для другой версии времени выполнения. По этой причине вы можете загрузить сборку с помощью Assembly.ReflectionOnlyLoadFrom для загрузки сборки только в отражении. Затем сборка не загружается в ваш домен приложения и не генерирует исключение.

person Ehsan Mohammadi    schedule 04.01.2013

Рисунок, который я мог бы также добавить в свое решение на основе linq (удобно, если вы просто ищете один файл и не хотите перечислять каждый файл)

функция поиска файлов:

    public static IEnumerable<string> FindFiles (string path, string filter = "", int depth = int.MaxValue) {
        DirectoryInfo di = new DirectoryInfo(path);

        IEnumerable<string> results = (! string.IsNullOrEmpty(filter) ? di.GetFiles(filter) : di.GetFiles()).Select(f => f.FullName);
        if (depth > 0) {
            results = results.Concat(di.GetDirectories().SelectMany(d => FindFiles(d.FullName, filter, depth - 1)));
        }

        return results;
    }

И для вызова (у меня не было Environment.SpecialFolder.Windows, поэтому вместо этого использовал Environment.SpecialFolder.System)

string path = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\..\\assembly";
foreach (string s in FindFiles(path, "*.dll")) {
     Console.WriteLine(s);
}

Кроме того, для справки, этот метод перебирает весь GAC, и вы можете найти дубликаты DLL в tmp/ и temp/, Tmp используется для установки, а Temp используется для удаления.

person katbyte    schedule 23.02.2013

Проверьте, как fusion.dll используется в ILSpy для перечислить все сборки GAC.

Оболочки Fusion COM

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace GacWithFusion
{
    // .NET Fusion COM interfaces
    [ComImport, Guid("CD193BC0-B4BC-11D2-9833-00C04FC31D2E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAssemblyName
    {
        [PreserveSig]
        int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty);

        [PreserveSig]
        int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty);

        [PreserveSig]
        int Finalize();

        [PreserveSig]
        int GetDisplayName([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder szDisplayName,
                           ref uint pccDisplayName,
                           uint dwDisplayFlags);

        [PreserveSig]
        int BindToObject(object refIID,
                         object pAsmBindSink,
                         IApplicationContext pApplicationContext,
                         [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase,
                         long llFlags,
                         int pvReserved,
                         uint cbReserved,
                         out int ppv);

        [PreserveSig]
        int GetName(ref uint lpcwBuffer,
                    [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwzName);

        [PreserveSig]
        int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow);

        [PreserveSig]
        int IsEqual(IAssemblyName pName,
                    uint dwCmpFlags);

        [PreserveSig]
        int Clone(out IAssemblyName pName);
    }

    [ComImport(), Guid("7C23FF90-33AF-11D3-95DA-00A024A85B51"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IApplicationContext
    {
        void SetContextNameObject(IAssemblyName pName);

        void GetContextNameObject(out IAssemblyName ppName);

        void Set([MarshalAs(UnmanagedType.LPWStr)] string szName,
                 int pvValue,
                 uint cbValue,
                 uint dwFlags);

        void Get([MarshalAs(UnmanagedType.LPWStr)] string szName,
                 out int pvValue,
                 ref uint pcbValue,
                 uint dwFlags);

        void GetDynamicDirectory(out int wzDynamicDir,
                                 ref uint pdwSize);
    }

    [ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAssemblyEnum
    {
        [PreserveSig]
        int GetNextAssembly(out IApplicationContext ppAppCtx,
                            out IAssemblyName ppName,
                            uint dwFlags);

        [PreserveSig]
        int Reset();

        [PreserveSig]
        int Clone(out IAssemblyEnum ppEnum);
    }

    internal static class Fusion
    {
        // dwFlags: 1 = Enumerate native image (NGEN) assemblies
        //          2 = Enumerate GAC assemblies
        //          4 = Enumerate Downloaded assemblies
        //
        [DllImport("fusion.dll", CharSet = CharSet.Auto)]
        internal static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum,
                                                      IApplicationContext pAppCtx,
                                                      IAssemblyName pName,
                                                      uint dwFlags,
                                                      int pvReserved);
    }
}

Главная

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace GacWithFusion
{
    public class Program
    {
        static void Main(string[] args)
        {
            foreach (var assemblyName in GetGacAssemblyFullNames())
            {
                Console.WriteLine(assemblyName.FullName);
            }
        }

        public static IEnumerable<AssemblyName> GetGacAssemblyFullNames()
        {
            IApplicationContext applicationContext;
            IAssemblyEnum assemblyEnum;
            IAssemblyName assemblyName;

            Fusion.CreateAssemblyEnum(out assemblyEnum, null, null, 2, 0);
            while (assemblyEnum.GetNextAssembly(out applicationContext, out assemblyName, 0) == 0)
            {
                uint nChars = 0;
                assemblyName.GetDisplayName(null, ref nChars, 0);

                StringBuilder name = new StringBuilder((int)nChars);
                assemblyName.GetDisplayName(name, ref nChars, 0);

                AssemblyName a = null;
                try
                {
                    a = new AssemblyName(name.ToString());
                }
                catch (Exception)
                {
                }

                if (a != null)
                {
                    yield return a;
                }
            }
        }
    }
}
person vrnithinkumar    schedule 19.03.2018

Возможно, вам понадобится программа просмотра GAC, например:

alt text" a>alt text"

Видео: как использовать диалоговое окно добавления ссылок GAC

Надеюсь это поможет

s

person BALKANGraph    schedule 29.04.2010
comment
Это не поможет, поскольку он сказал, что у него есть только FTP-доступ к серверу. Он хочет иметь возможность перечислять GAC, используя код C#, который выполняется в среде с неполным доверием. - person BrainSlugs83; 17.02.2012