Подтвердить что ты не робот

Плагиновая структура с ASP.NET MVC3 и встроенными представлениями Razor

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

Плагиновая структура предназначена для использования этих функций:

  • Каждый плагин имеет свои собственные модели, контроллеры и представления. Представления представляют собой встроенные ресурсы, а контроллеры - из класса PluginController
  • У плагинов есть ссылки зависимостей на общую библиотеку классов, которая определяет базовый класс PluginController
  • Веб-приложение "shell", в котором размещаются плагины , не должно содержать ссылки на любые плагины во время разработки, так как во время разработки он не знает, какие плагины он имеет.
  • Плагины dll отбрасываются в папку в приложении оболочки, которая не папка /bin
  • Корпус заботится:
    • Обнаружение плагинов (с использованием отражения)
    • Регистрация всех контроллеров (я использую Spring.Net для этого)
    • Создание маршрутов к контроллерам
    • Обслуживание файлов бритвы (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), и рассматривать их как "граждан первого класса", чтобы их можно было использовать в виде бритвы?

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

MyLibrary MyLibrary.Templates

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