Каркас плагина с ASP.NET MVC3 и встроенными представлениями Razor - PullRequest
13 голосов
/ 24 июня 2011

Я разрабатываю инфраструктуру плагинов для ASP.NET MVC3 с использованием представлений Razor, и у меня возникла проблема с тем, чтобы встроенные представления работали правильно.

Каркас плагина имеет следующие особенности:

  • Каждый плагин имеет свои модели, контроллеры и представления. Представления: встроенные ресурсы , а контроллеры являются производными от класса PluginController
  • Плагины имеют ссылки на зависимости от общей библиотеки классов, которая определяет базовый класс PluginController
  • Веб-приложение "shell", в котором размещаются плагины , не должно содержать ссылок на какие-либо плагины во время разработки , поскольку во время разработки оно не знает, какие плагины оно имеет.
  • DLL-файлы плагина сбрасываются в папку в приложении оболочки, которая является , а не папкой / bin
  • Оболочка заботится о:
    1. Обнаружение плагинов (используя отражение)
    2. Регистрация всех контроллеров (для этого я использую Spring.Net)
    3. Создание маршрутов к контроллерам
    4. Обслуживание бритвенных файлов (cshtml) через пользовательский VirtualPathProvider

Теперь все работает нормально, кроме случаев, когда встроенные представления имеют ссылки на типы в dll плагина. Тогда я получаю позорную ошибку (имена опущены):

The type or namespace name '[Plugins]' does not exist in the namespace '[MyPluginSolution]' (are you missing an assembly reference?)

Причина этого заключается в том, что компилятор csc, который вызывается во время выполнения для компиляции видов бритв , получает только ссылки на dll из папки bin и GAC .

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

Конечно, я мог бы удалить плагин dll в папке / bin, но мой вопрос:

Есть ли способ зарегистрировать dll в папке не-bin (и не-GAC) и обращаться с ними как с "первоклассными гражданами", чтобы их могли использовать виды бритвы?

Ответы [ 6 ]

14 голосов
/ 27 июня 2011

Хорошо, решение было найдено с помощью этой статьи .

Сначала я создаю класс с PreApplicationStartMethod. Этот метод сканирует папку плагина и копирует dll в AppDomain.DynamicDirectory.

Затем каждый из этих DLL загружается с помощью BuildManager.AddReferencedAssembly.

И вуаля, строго типизированные виды Razor прекрасно компилируются. Смотрите код здесь:

[assembly: PreApplicationStartMethod(typeof(MySolution.PluginHandler.PluginActivator), "Initialize")]
namespace MySolution.PluginHandler
{
    public class PluginActivator
    {
        private static readonly DirectoryInfo PluginFolderInfo;

        static PluginActivator() {
            PluginFolderInfo = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins"));
        }

        public static void Initialize() {
            CopyPluginDlls(PluginFolderInfo, AppDomain.CurrentDomain.DynamicDirectory);
            LoadPluginAssemblies(AppDomain.CurrentDomain.DynamicDirectory);
        }

        private static void CopyPluginDlls(DirectoryInfo sourceFolder, string destinationFolder)
        {
            foreach (var plug in sourceFolder.GetFiles("*.dll", SearchOption.AllDirectories)) {
                if (!File.Exists(Path.Combine(destinationFolder, plug.Name))) {
                    File.Copy(plug.FullName, Path.Combine(destinationFolder, plug.Name), false);
                }
            }
        }

        private static void LoadPluginAssemblies(string dynamicDirectory)
        {
            foreach (var plug in Directory.GetFiles(dynamicDirectory, "*.dll", SearchOption.AllDirectories)) {
                Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(plug));
                BuildManager.AddReferencedAssembly(assembly);
            }
        }
    }
}

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

1 голос
/ 28 марта 2013

Вы также можете перейти к функции «Площадь» в MVC3 и 4, вы можете создать хорошую систему плагинов. Это дает разделение модели, представления и контроллера плагина в его собственной сборке.

1 голос
/ 11 марта 2013

Пожалуйста, ознакомьтесь с исходным кодом NOPCommerce. У этого есть хорошая структура плагина, основанная на работе Шеннон .

1 голос
/ 24 июня 2011

Проверьте MEF

Вы также можете сделать это с помощью Виндзорских Установщиков - у Майка Хэдлоу хороший удар по этому вопросу: http://mikehadlow.blogspot.com/2010/10/experimental-aspnet-mvc-add-ins-updated.html

1 голос
/ 24 июня 2011

Дэвид Эббо недавно написал в блоге о предварительной компиляции представлений Razor в сборки. Вы можете просмотреть сообщение здесь .

Вы должны быть в состоянии избежать регистрации сборок напрямую, динамически загружая сборки (я бы обычно использовал для этого свой контейнер IoC), а затем вызывая BuildManager.AddReferencedAssembly для каждой сборки плагина.

0 голосов
/ 17 мая 2012

Вы можете найти это полезным http://www.adverseconditionals.com/2011/07/portable-aspnet-code-using.html

Я начал создавать два проекта

MyLibrary MyLibrary.Templates

и имеют представления в виде содержимого в .Templates, добавляются в виде ссылок и устанавливаются в EmbeddedResource в MyLibrary. Люди, которые хотят переопределить представления, могут установить проект .Templates.

...