Перечисление сборок в GAC
Как я могу перечислять все доступные сборки в GAC в С#?
На самом деле я столкнулся с проблемой с глупым кодом - сборка, называемая Telerik.Web.UI.dll, передается и используется в проекте - эта конкретная DLL отсутствует в папке BIN. И приложение отлично работает на сервере - но на моей машине, очевидно, компилятор дает ошибку. Экс-разработчик настаивает на том, что он не находится в GAC на сервере и "это то, что есть". Теперь мне нужно проверить, зарегистрирована ли эта DLL в GAC или нет.
Помощь будет оценена.
Добрый день;
Ответы
Ответ 1
Если у вас ограниченный доступ к серверу, это может сработать:
// 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, поэтому может работать в вашей среде хостинга.
Его можно было бы украсить, перечислив глубже в каждую папку сборки, чтобы вытащить номер версии и токен открытого ключа.
Ответ 2
Проверьте этот codeproject GAC API Interface. Это использует недокументированный файл fusion.dll для перечисления GAC. Но автор утверждает, что
Этот код, как известно, работает с .NET. 1.1 и 2.0. Обратите внимание, что DLL fusion.dll отличается в 1.1 и 2,0. Поэтому, если у вас установлены оба фреймворка, обязательно укажите код в нужную DLL. В противном случае большинство API-вызовы не удастся. По умолчанию реализация использует ту, которая найдена в каталог WINDOWS.
Ответ 3
Вам действительно не нужно писать что-то на С#, чтобы узнать, находится ли эта конкретная DLL в gac. Вы можете использовать gacutil.exe с параметром /l из командной строки, чтобы отобразить содержимое GAC.
Ответ 4
Если это простой сайт ASP.NET, а сборка не находится в папке bin или на сервере GAC (и в web.config нет ничего подозрительного), возможно, сайт является подсайтом какой-то тип и один из сайтов выше, содержит ссылку в папке bin (или что-то подозрительное в ее web.config, поскольку подсайты/папки наследуют веб файлы своих родителей)?
Теперь, если у вас есть среда, в которой файл загружается правильно (и это похоже на то, что вы делаете), вы можете просто спросить .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, если вы уже ссылаетесь на сборку, вы можете перечислить сборки, загруженные в текущее приложение .domain, и просто распечатать (или визуализировать литеральный элемент управления или Response.Write и т.д.)....), каковы их свойства .Location.
Edit:
Код для этого выглядит примерно так:
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine(a.GetName().FullName);
Console.WriteLine(a.Location);
Console.WriteLine();
}
Edit:
В полной среде доверия следующий код (консольное приложение) перечислит 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");
}
Ответ 5
простой способ перечислить 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, чтобы загрузить сборку только в отражении. Затем Assembly не загружается в AppDomain и не генерирует исключение.
Ответ 6
Рисунок я мог бы также добавить мое решение на основе 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);
}
Кроме того, в качестве FYI этот метод перечисляет весь GAC, и вы можете найти дубликаты DLL в tmp/и temp/, для установки используется Tmp, а для удаления используется Temp.
Ответ 7
Проверьте, как fusion.dll используется в ILSpy для перечисления всех сборок GAC.
Fusion COM Wrappers
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;
}
}
}
}
}
Ответ 8
Возможно, вам нужен просмотрщик GAC примерно так:
![alt text]()
Видео: Как использовать диалог добавления ссылок GAC
Надеюсь, что это поможет
s