2013-03-23 1 views
0

Чтобы включить сложный сценарий отладки, мне нужна моя сборка, чтобы выяснить, где находятся исходные файлы во время выполнения.Как узнать каталог проекта сборки?

Assembly объект не знает эту информацию, и это, вероятно, не должно. Файл .pdb явно знает, но я понятия не имею, как его разобрать. Так что я подумал, что я могу маркировать свою сборку во время сборки с атрибутом, то эффект:

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

Я не могу использовать текущий каталог, так как он установлен IIS в какой-то временный каталог во время отладки. Я также не хочу жестко закодировать каталог.

Ближайший, к которому я пришел, в решении этого вопроса, использует свойство Assembly.CodeBase. Он указывает на каталог, в котором было построено решение IIS (Solution/IISProject/bin/Debug/, а не /Solution/source/MyLibrary/), но не каталог моего проекта. Хакерное решение поднимается на несколько уровней оттуда, а затем переходите на несколько уровней обратно в папку проекта. Я бы очень хотел избежать этого взлома, если это возможно.

+0

Зачем вам это нужно? Если вы можете сказать нам, почему это интересная информация для хранения, то, возможно, мы сможем предложить вам альтернативные решения. Я не думаю, что есть встроенный способ получить то, что вы хотите. –

+0

@ LasseV.Karlsen Мне нужно это, чтобы иметь возможность перекомпилировать части решения (эти части являются языком, специфичным для домена) во время выполнения отладки. Я уверен, что есть что-то, что можно сделать. Моя первая мысль состояла в том, чтобы проанализировать .pdb, который, очевидно, имеет эту информацию, но, по-видимому, это нелегко разобрать. – Gleno

ответ

0

Для включения этих типов сценариев, как правило, лучше всего разместить эти каталоги в настройках вашего web.config. Поэтому вы можете сказать, основываясь на данной ситуации, использовать этот каталог вместо этого каталога. Часто люди используют, если (IsDebugging) используют этот каталог, иначе используйте этот каталог.

0

После большого поиска души мне удалось собрать достаточно inspiration, чтобы составить следующий фрагмент. Идея состоит в том, чтобы использовать файл .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(); 
    } 
}