简体   繁体   English

如何找到装配体的项目目录?

[英]How to find out the project directory of an assembly?

To enable an elaborate debugging scenario, I need my assembly to figure out where the source files are at run-time. 为了启用详尽的调试方案,我需要我的程序集来确定源文件在运行时的位置。

The Assembly object doesn't know this information, and it probably shouldn't. Assembly对象不知道此信息,也可能不知道。 The .pdb file obviously knows, but I have no idea how to parse it. .pdb文件显然知道,但是我不知道如何解析它。 So I thought maybe I can tag my assembly at build time with an attribute, something to the effect of: 所以我想也许可以在构建时用属性标记我的程序集,从而达到以下效果:

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

I can't use the current directory, since it's set by IIS to some temporary directory during debugging. 我无法使用当前目录,因为在调试过程中IIS将其设置为某个临时目录。 Nor do I want to hard-code the directory. 我也不想对目录进行硬编码。

The closest I've come so far in solving this, is using the Assembly.CodeBase property. 到目前为止,我解决这个问题最接近的方法是使用Assembly.CodeBase属性。 It points to the directory where the IIS solution was built ( Solution/IISProject/bin/Debug/ , rather than /Solution/source/MyLibrary/ ), but not my project directory. 它指向构建IIS解决方案的目录( Solution/IISProject/bin/Debug/ ,而不是/Solution/source/MyLibrary/ ),而不是我的项目目录。 A hacky solution is going up a few levels from there, then go down a few levels back to the project folder. 一个骇人听闻的解决方案从那里上升了几层,然后下降了几层回到项目文件夹。 I would very much like to avoid this hack if possible. 如果可能的话,我非常想避免这种黑客攻击。

To enable these types of scenarios usually the best practice is to place these directories in a setting in your web.config. 通常,要启用这些类型的方案,最佳实践是将这些目录放在web.config中的设置中。 So you can say based on a given situation, use this directory instead of this directory. 因此,您可以根据特定情况说,使用此目录而不是此目录。 Often people use if (IsDebugging) use this dir, else use this dir. 人们经常使用if(IsDebugging)使用此目录,否则使用此目录。

After a lot of soul searching, I managed to collect enough inspiration to compose the following snippet. 经过大量的灵魂搜索,我设法收集了足够的灵感来编写以下代码段。 The idea is to use the .pdb file to discover the location of the source code. 这个想法是使用.pdb文件来发现源代码的位置。 You need to reference ISymWrapper.dll and compile in 32 bits mode. 您需要引用ISymWrapper.dll并以32位模式进行编译。 If there's a simpler method around, I'd be glad to hear it. 如果有更简单的方法,我很高兴听到。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM