0

为了启用复杂的调试方案,我需要我的程序集找出源文件在运行时的位置。

Assembly对象不知道这些信息,而且它可能不应该知道。该.pdb文件显然知道,但我不知道如何解析它。所以我想也许我可以在构建时使用属性标记我的程序集,效果如下:

[assembly: AssemblyMetadata("ProjectDirectory", $(ProjectDir))]

我不能使用当前目录,因为它是由 IIS 在调试期间设置为某个临时目录的。我也不想对目录进行硬编码。

到目前为止,我在解决这个问题方面最接近的是使用该Assembly.CodeBase属性。它指向构建 IIS 解决方案的目录(Solution/IISProject/bin/Debug/而不是/Solution/source/MyLibrary/),但不是我的项目目录。一个 hacky 解决方案是从那里上升几级,然后再下降几级回到项目文件夹。如果可能的话,我非常想避免这种黑客攻击。

4

2 回答 2

0

经过一番深思熟虑,我设法收集到足够的灵感来撰写以下片段。这个想法是使用.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();
    }
}
于 2013-03-23T19:46:02.343 回答
0

要启用这些类型的方案,最佳实践通常是将这些目录放在 web.config 中的设置中。所以你可以根据给定的情况说,使用这个目录而不是这个目录。人们经常使用 if (IsDebugging) 使用这个目录,否则使用这个目录。

于 2013-03-23T16:22:04.377 回答