Listing Assemblies in the GAC

How can I list all available assemblies in the GAC in C #?

In fact, I ran into a problem with stupid code - an assembly called Telerik.Web.UI.dll is passed and used in the project - this particular DLL is not in the BIN folder. And the application works fine on the server - but on my machine, obviously, the compiler gives an error. The ex-developer insists that he is not in the GAC on the server and "this is what it is." Now I need to check if this DLL is registered in the GAC or not.

Help will be appreciated.

Good afternoon;

+11
source share
8 answers

If you have limited access to the server, this might work:

// 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/>"); } } } 

Mainly lists raw GAC folders. It runs on a DiscountASP distributed host, so it can work in your hosting environment.

It could be decorated by listing deeper into each build folder to pull out the version number and public key token.

+10
source

Check out this codeproject GAC API Interface . This uses the undocumented fusion.dll file to list the GAC. But the author claims that

This code is known to work with .NET. 1.1 and 2.0. Note that the fusion.dll DLL is different in 1.1 and 2.0. Therefore, if you have both frameworks installed, be sure to specify the code in the correct DLL. Otherwise, most of the API calls will fail. By default, the implementation uses the one found in the WINDOWS directory.

+4
source

You really don't need to write something in C # to find out if this particular dll is in gac. You can use gacutil.exe with the / l switch from the command line to display the contents of the GAC.

+4
source

If this is a simple ASP.NET site, and the assembly is not located in the bin folder or on the GAC server (and there is nothing suspicious in web.config), it is possible that the site is a sub-site of some type and one of the sites above contains a link in the bin folder (or something suspicious of its web.config, since sub-sites / folders inherit their parents' web files)?

Now, if you have an environment in which the file loads correctly (and this looks like what you are doing), you can just ask .NET where the .dll comes from and display it instead, for example:

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

The assembly will load and display its location on the disk, my conclusion is: C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Shell\2.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Shell.dll

If it is under "C: \ Windows \ assembly \", you know this in the GAC.

You can also do this without calling Assembly.Load, if you already reference the assembly, you can list the assemblies loaded in the current .domain application and just print it (or visualize a literal control or Response.Write, etc.). ...) what are their .Location properties.

Edit: The code for this looks something like this:

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

Edit: In a complete trust environment, the following code (console application) will list the GAC and write each assembly, so it is easy to change it in an ASP.NET application, but I'm not sure that it will work in an environment that is less than full trust (just guessing here , you may be lucky):

 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"); } 
+3
source

easy way to list dll files in a directory

 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(); } 

and you can get all the files

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

If you need to load each assembly, you will get an exception for different versions at runtime. For this reason, you can load the assembly Assembly.ReflectionOnlyLoadFrom to load the assembly in reflection only. Then Assembly does not load into the AppDomain and does not throw an exception.

+3
source

Figure I could also add my linq-based solution (handy if you're just looking for one file and don't want to list through each file)

to find files:

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

And for the call (I did not have Environment.SpecialFolder.Windows, so Environment.SpecialFolder.System was used instead)

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

In addition, as the FYI, this method lists the entire GAC, and you can find duplicate DLLs in tmp / and temp /, Tmp is used for installation, and Temp is used for removal.

+1
source

Check how fusion.dll is used in ILSpy to list all GAC assemblies.

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); } } 

home

 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; } } } } } 
0
source

Perhaps you need a GAC ​​viewer like this:

alt text

Video: How to use the GAC Add Link dialog

Hope this helps

s

-3
source

All Articles