如何查找程序集的项目目录
本文关键字:项目 程序集 何查找 查找 | 更新日期: 2023-09-27 18:05:33
要启用一个详细的调试场景,我需要我的程序集找出源文件在运行时的位置。
Assembly
对象不知道这个信息,它可能也不应该知道。.pdb
文件显然知道,但我不知道如何解析它。所以我想也许我可以在构建时用一个属性标记我的程序集,效果是:
[assembly: AssemblyMetadata("ProjectDirectory", $(ProjectDir))]
我不能使用当前目录,因为IIS在调试期间将其设置为某个临时目录。我也不想硬编码这个目录。
到目前为止,我在解决这个问题上最接近的是使用Assembly.CodeBase
属性。它指向构建IIS解决方案的目录(Solution/IISProject/bin/Debug/
,而不是/Solution/source/MyLibrary/
),但不是我的项目目录。一个简单的解决方案是,从那里往上走几层,然后再往下走几层,回到项目文件夹。如果可能的话,我非常希望避免这种攻击。
要启用这些类型的场景,通常最佳实践是将这些目录放在web.config中的设置中。所以你可以说,根据给定的情况,用这个目录代替这个目录。通常人们使用if (IsDebugging)使用这个目录,否则使用这个目录。
经过一番深思熟虑,我设法收集了足够的灵感来编写下面的代码片段。其思想是使用.pdb
文件来发现源代码的位置。您需要引用ISymWrapper.dll
并在32位模式下编译。如果有更简单的方法,我很乐意听听。
using System;
using System.Diagnostics.SymbolStore;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Linq;
public static class AssemblyDirectoryInfo
{
private const string
ImporterId = "7DAC8207-D3AE-4c75-9B67-92801A497D44",
DispenserId = "809c652e-7396-11d2-9771-00a0c9b4d50c",
DispenserClassId = "e5cb7a31-7512-11d2-89ce-0080c792e5d8";
[Guid(ImporterId), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true)]
public interface IMetaDataImport{}
[Guid(DispenserId), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true)]
interface IMetaDataDispenser
{
void DefineScope();
void OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] String szScope, [In] Int32 dwOpenFlags,
[In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object punk);
}
[DllImport("ole32.dll")]
private static extern int CoCreateInstance([In] ref Guid guid,
[In, MarshalAs(UnmanagedType.IUnknown)] Object pUnkOuter,
[In] uint dwClsContext,
[In] ref Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out Object ppv);
public static DirectoryInfo GetAssemblyCodeBase(Assembly assembly)
{
var file = new FileInfo(assembly.Location);
Guid dispenserClassId = new Guid(DispenserClassId),
importerIid = new Guid(ImporterId),
dispenserIid = new Guid(DispenserId);
object dispenser, importer;
CoCreateInstance(ref dispenserClassId, null, 1, ref dispenserIid, out dispenser);
((IMetaDataDispenser)dispenser).OpenScope(file.FullName, 0, ref importerIid, out importer);
var ptr = Marshal.GetComInterfaceForObject(importer, typeof(IMetaDataImport));
var reader = new SymBinder().GetReader(ptr, file.FullName, file.DirectoryName);
return reader.GetDocuments()
.Select(d => d.URL)
.Where(v => !string.IsNullOrEmpty(v))
.OrderBy(v => v.Length)
.Select(v => new FileInfo(v).Directory)
.First();
}
}