[英]enumerating assemblies in 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<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共享主機,因此可能適用於您的托管環境。
它可以通過枚舉更深入到每個程序集的文件夾來修飾版本號和公鑰令牌。
查看此代碼項目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的內容。
枚舉目錄中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加載程序集,僅在反射中加載程序集。 然后,程序集不會加載到您的AppDomain中,也不會拋出異常。
如果它是普通的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中。
如果你已經引用了程序集,你可以枚舉加載到當前app.domain中的程)他們的.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");
}
圖我可以投入我的基於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,您可能會在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<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;
}
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.