Сборка не может найти ссылочную сборку при компиляции в память с CodeDomProvider - PullRequest
5 голосов
/ 24 июля 2011

Я пытаюсь скомпилировать некоторый код в память во время выполнения, используя CodeDomProvider.

Код, который я компилирую, имеет ссылку на внешнюю сборку, которую я включаю в параметры, используемые при компиляции кода.

Когда я компилирую в память и пытаюсь использовать отражение в сборке, сгенерированной в надстройке Visual Studio, возникает исключение, говорящее о том, что он не может найти указанную сборку.

(Exception)
«Невозможно загрузить один или несколько запрошенных типов. Получите свойство LoaderExceptions для получения дополнительной информации.»

(LoaderException)
"{" Не удалось загрузить файл или сборку 'Dynamo.Jiss.Task, версия = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null' или одна из его зависимостей. Системе не удается найти указанный файл. ":" Dynamo.Jiss.Task, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = null "}"

Я пытался ссылаться на сборку из разных мест, используя абсолютный путь.

Точно такой же код отлично работает, если он запускается из консольного приложения, а также отлично работает в надстройке, если я не компилирую в память.
Удаление ссылки на внешнюю сборку и кода, который ссылается на нее, также работает при компиляции в память, поэтому, вероятно, как описывает исключение, возникает проблема с загрузкой ссылочной сборки.

У кого-нибудь есть идея, почему компиляция в память и ссылка на сборку не работают в надстройке?

Существуют ли какие-то ограничения в пределах домена приложения, в котором он запущен, или что-то, о чем я должен знать? (мое лучшее предположение в настоящее время)

Должно ли оно быть в определенной папке? ссылаться с использованием относительного пути? Настройки безопасности? нужно подписать? есть идеи?


То, чего я пытаюсь добиться, - это способ поместить файлы с определенным расширением в проект и позволить надстройке автоматически скомпилировать его, и если он реализует интерфейс ITask (из внешней сборки), он вызовет метод Setup () это позволяет коду подключаться к событиям Visual Studio и выполнять задачи / сценарии во время прослушивания различных событий. Таким образом, я могу легко выполнить текстовые шаблоны, если другой файл будет изменен, или объединить и свернуть файлы для различных событий (документ сохранен, сборка и т. Д.).

Уже существует что-то подобное (чтобы избавить меня от боли)? :)

1 Ответ

9 голосов
/ 24 июля 2011

Скорее всего, это происходит потому, что вы приказываете CodeDom сгенерировать сборку в памяти (что на самом деле является ложью, поскольку она временно генерирует диск, загружает его, а затем удаляет файл). Дело в том, что каталог компиляции для сборки CodeDom отличается от каталога, который вы используете для его компиляции. То есть, если вы работаете в bin \ Debug, сборка CodeDom генерируется в% temp%.

Вы можете решить это одним из двух способов, о которых я могу подумать:

  1. Скомпилируйте сборку CodeDom по тому же пути, что и ваша исполняемая сборка.

    myCodeProvider.GenerateInMemory = false; // may not be necessary...haven't tried this in a while
    myCodeProvider.OutputAssembly = string.Format(@"{0}\{1}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location, "mydll.dll");
    
  2. Обработайте событие AssemblyResolve и предоставьте сборке CodeDom запрашиваемую ссылочную сборку.

    AppDomain.CurrentDomain.AssemblyResolve += OnCurrentDomainAssemblyResolve
    
    private static Assembly OnCurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
    {
                    // this is absurdly expensive...don't do this more than once, or load the assembly file in a more efficient way
                    // also, if the code you're using to compile the CodeDom assembly doesn't/hasn't used the referenced assembly yet, this won't work
                    // and you should use Assembly.Load(...)
                    foreach (Assembly @assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        if (@assembly.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            return @assembly;
                        }
                    }
    }
    
...