Помогите System.Web.Compilation.BuildManager найти тип в несвязанной сборке

Я пытаюсь написать систему плагинов, в которой сборки можно помещать в папку, о которой ASP.NET не знает. Эта система плагинов прекрасно работает для сборок на основе ASP.NET MVC, но для сборок старой школы WebForm (где .aspx файлы Inherits System.Web.UI.Page производные классы) System.Web.Compilation.BuildManager отвечает за составление .aspx файл в динамическую сборку.

Моя проблема в том, что BuildManager ничего не знает о сборках в моей папке плагинов, и, похоже, я ничего не могу сделать, чтобы помочь этому. Если я сделаю:

BuildManager.GetType("PluginAssembly.DefinedType", true, true)

это бросает. Если я впервые получу ссылку на Type а затем попробуйте:

var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);

это все еще бросает, хотя я теперь прошел в конкретном type это должно скомпилировать .aspx файл. Могу ли я чем-нибудь помочь? BuildManager найти типы, необходимые для компиляции .aspx файл?

Обновление: я сделал еще один шаг вперед, посмотрев, что BuildManager.GetType() на самом деле Указывая сборку, в которой определяется тип (такой как "PluginAssembly.DefinedType, PluginAssembly"), а затем подключая себя к System.AppDomain.CurrentDomain.AssemblyResolve Теперь я могу найти сборку плагина и вернуть ее, чтобы BuildManager мог успешно сконструировать тип. Это делает следующую работу с летающими цветами:

BuildManager.GetType("PluginAssembly.DefinedType, PluginAssembly", true, true)

Однако, это все еще терпит неудачу:

var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);

Хотя .aspx файл теперь имеет такую ​​же ссылку на сборку в своем Inherits директива:

<%@ Page Language="C#"              
         CodeBehind="Index.aspx.cs"
         Inherits="PluginAssembly.DefinedType, PluginAssembly" %>

Я получаю ошибку:

"Сообщение об ошибке компилятора: CS0234: имя типа или пространства имен" DefinedType "не существует в пространстве имен" PluginAssembly "(отсутствует ссылка на сборку?)" Со следующими исходными данными:

Line 205:
Line 206:    [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
Line 207:    public class plugins_pluginassembly_dll_index_aspx
                 : global::PluginAssembly.DefinedType,
                   System.Web.SessionState.IRequiresSessionState, 
                   System.Web.IHttpHandler {
Line 208:        
Line 209:        private static bool @__initialized;

Кажется, что происходит внутри BuildManager.CreateInstanceFromVirtualPath() включает в себя определенный System.Web.Util.IWebObjectFactory что он может быть ответственным за создание этого исключения, не найдя мою сборку. Я могу реализовать этот интерфейс без каких-либо проблем, но что это поможет, если я не могу сказать BuildManager об этом?

4 ответа

Решение

В итоге я решил эту проблему с помощью проектов веб-развертывания [1], предварительно скомпилировав все веб-приложение в две отдельные сборки, а затем углубившись в нужную сборку с Assembly.GetTypes() чтобы создать правильный Page для данного HTTP-запроса.

Это больше ложится на плечи разработчиков плагинов, но дает лучшую производительность с дополнительным преимуществом полной проверки всех плагинов компилятором ASP.NET перед их выполнением в (чувствительном к безопасности и хрупком) веб-контексте.,

Я не знаю как BuildManager загружает типы, но вы можете попробовать использовать AssemblyResolve - подписаться на AppDomain.CurrentDomain.AssemblyResolve событие, и загрузить сборку самостоятельно и вернуть (да, вернуть) Assembly экземпляр (или null если ты не узнаешь это).

Не весь такой код использует подходы, совместимые с этим, но это стоит попробовать.

Я вижу два способа указать сборки, используемые для компиляции страницы:

  • Вызов BuildManager.AddReferencedAssembly (но я полагаю, вы уже пробовали это?)
  • Помещение в конфигурацию виртуального каталога страницы компиляции списка необходимых сборок (в разделе system.web/compilation/ сборки) и доступность этих сборок в домене приложения (среда, кажется, использует Assembly.Load для поиска сборок, найденных в конфигурации. файлы).

Я сам разрабатываю ленивый фреймворк загрузки для ASP.NET. Ваши плагины всегда могут использовать <@ Assembly> директива на их страницах, чтобы вручную ссылаться на сборку.

Другие вопросы по тегам