枚举GAC中的程序集

如何在C#中枚举GAC中的所有可用程序集?

实际上我遇到了一个愚蠢的代码问题 – 名为Telerik.Web.UI.dll的程序集在项目中被引用和使用 – 这个特定的DLL在BIN文件夹中不存在。 应用程序在服务器上工作正常 – 但在我的机器上,显然编译器给出了错误。 Ex-Developer坚持认为它不在服务器上的GAC中,而是“它就是这样”。 现在我需要检查这个DLL是否在GAC中注册。

帮助将不胜感激。

美好的一天;

如果您对服务器的访问权限有限,那么这可能有效:

// List of all the different types of GAC folders for both 32bit and 64bit // environments. List gacFolders = new List() { "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("
" + folder + "
"); string[] assemblyFolders = Directory.GetDirectories(path); foreach (string assemblyFolder in assemblyFolders) { Response.Write(assemblyFolder + "
"); } } }

它基本上枚举了原始GAC文件夹。 它适用于DiscountASP共享主机,因此可能适用于您的托管环境。

它可以通过更深入地枚举每个程序集的文件夹来修饰版本号和公钥令牌。

查看此代码项目GAC API接口文章。 这使用未记录的fusion.dll来累积GAC。 但作者声称

已知此代码可与.NET 1.1和2.0一起使用。 请注意,DLL fusion.dll在1.1和2.0中有所不同。 因此,如果您安装了两个框架,请确保将代码指向正确的DLL。 否则大多数API调用都将失败。 默认实现使用WINDOWS目录中的实现。

你真的不需要在C#中写一些东西来找出这个特定的dll是否在gac中。 您可以在命令行中使用带有/ l选项的gacutil.exe来列出GAC的内容。

如果它是普通的ASP.NET站点,并且程序集不在站点的bin文件夹中或服务器的GAC中(并且web.config中没有任何可疑内容),那么该站点可能是某种类型的子站点,其中一个网站的更高版本包含bin文件夹中的引用(或者其web.config中的某些内容,因为子网站/文件夹inheritance了其父级的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"); } 

枚举目录中dll文件的简单方法

 public static string[] GetGlobalAssemblyCacheFiles(string path) { List files = new List(); 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); 

如果需要加载每个程序集,则会获得不同运行时版本的exception。 因此,您可以使用Assembly.ReflectionOnlyLoadFrom加载程序集,仅在reflection中加载程序集。 然后,程序集不会加载到您的AppDomain中,也不会抛出exception。

图我可能会抛出我的基于linq的解决方案(如果您只是寻找单个文件并且不想枚举每个文件,那么就很方便)

找到文件的function:

  public static IEnumerable FindFiles (string path, string filter = "", int depth = int.MaxValue) { DirectoryInfo di = new DirectoryInfo(path); IEnumerable 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,您可能会在tmp /和temp /中找到重复的DLL,Tmp用于安装,Temp用于卸载。

检查在ILSpy中如何使用fusion.dll枚举所有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 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; } } } } } 

可能你需要这样的GAC查看器:

替代文字

video:如何使用“添加GAC参考”对话框

希望这可以帮助

小号