У меня возникли проблемы с разрешением 404 ответов в моем проекте Asp.Net MVC 4. Он построен в VS2012, ориентированном на 4.5.
У меня есть предварительно скомпилированные представления и контроллеры, встроенные в автономные библиотеки DLL. Я могу динамически загружать библиотеки DLL и проверять их из моего основного проекта, даже вызывать методы на них; однако, похоже, что MVC Framework не знает контроллеров. Я здесь близко, но чего-то не хватает.
Фон на контроллерах и представлениях
Контроллеры построены в автономном проекте MVC и наследуются от Controller
. Ничего интересного не происходит. Представления используют RazorGenerator и становятся классами, которые живут в проекте.
Результатом проекта является DLL, которая правильно содержит контроллеры и представления.
DLL реализуют определенный интерфейс, мы будем называть его IPlugin
в отдельном классе (не являющемся частью контроллера) в библиотеке.
Загрузка DLL
Запуск в качестве администратора в Visual Studio Я скомпилирую свое приложение, которое размещено под IIS. С построенным проектом я бросаю DLL плагина в каталог "Плагины". Без отладки (это становится важным позже) я открываю IE и перехожу на сайт. Обратите внимание, что на данный момент приложение создано, но никогда не запускается, поэтому запускаются события запуска. Все здесь по-прежнему непротиворечиво, если я повторно использую пул приложений.
У меня есть класс Startup
с двумя методами, PreStart
и PostStart
и вызывать методы, используя WebActivator.PreApplicationStartMethod
и WebActivator.PostApplicationStartMethod
соответственно.
PreStart
, где я делаю следующее:
- Получить список всех DLL-модулей плагина в моем каталоге "Плагины"
- Скопируйте все плагины на
AppDomain.CurrentDomain.DynamicDirectory
- Загрузите тип... если он содержит
IPlugin
I, тогда- Добавить сборку в BuildManager
- Вызвать некоторые из методов класса, реализующего IPlugin
В 'PostStart' я делаю этот бит кода (на основе кода RazorGenerator.Mvc):
foreach (var assembly in Modules.Select(m=>m.Value))
{
var engine = new PrecompiledMvcEngine(assembly)
{
UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
};
ViewEngines.Engines.Insert(0, engine);
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
Modules
в этом контексте является парой ключ/значение, где значения представляют собой загруженные сборки. Цель этого кода - убедиться, что MVC осведомлен о представлениях, добавив механизм просмотра для каждой сборки, который знает, как разрешить представления (это часть RazorGenerator).
Как я знаю, что я закрыт (но явно не хватает сигары)
IPlugin
определяет метод под названием RegisterRoutes
, где, как вы догадались, маршруты должны быть зарегистрированы для тех, кто реализует интерфейс. Я вызываю этот метод в PreStart
и добавляются маршруты - я проверил, что они существуют в моей таблице маршрутов. Например, на маршруте, определенном в моем плагине, создаваемом динамическим вызовом метода во время PreStart
, я вижу что-то вроде этого как DataToken при рассмотрении моих маршрутов:
Namespaces = Plugin.Name.Controllers
Итак, маршрут зарегистрирован, сборка загружена, я проверил, что DLL правильно скопирована в DynamicDirectory AppDomain. Я могу вызвать участников классов, которые динамически загружаются во время выполнения. Но когда я перехожу к URL-адресу, который соответствует маршруту , я получаю 404. Это не "не удалось найти вид" YSOD, он более сродни не обнаружению контроллера вообще.
Вот часть, которая смущает меня из-за меня: если на данный момент, ничего не делая, я возвращаюсь в Visual Studio и нажимаю F5... все работает.
Это похоже на то, что Visual Studio осознает контроллер каким-то образом, который я не могу определить, и MVC Framework подбирает его.
Наконец, вопрос
Что мне не хватает, и как мне получить MVC Framework о моем контроллере?
И в этот момент, если вы все еще читаете это, спасибо.:)