MVC3 - Скомпилированное представление Razor не может найти _ViewStart - PullRequest
5 голосов
/ 08 февраля 2012

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

Я следовал руководству Криса Ван Де Стида здесь и только отклонилсяпрежде всего в части о добавлении ссылок, поскольку я загружаю свои сборки во время выполнения.

Поскольку я загружаю сборки во время выполнения, я не использую VirtualPathProviderViewEngine в библиотеке BoC, и вместо этого реализовал мойсобственный ViewEngine на основе RazorViewEngine.Он работает путем переписывания viewPath в CreateView для вставки соответствующего пространства имен, чтобы можно было разрешить представление.

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

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

У меня есть настройка маршрута, подобная этой: -

RouteTable.Routes.MapRoute(
    string.Format("Plugin{0}Route", pluginName),
    string.Format(@"Plugin/{0}/{{controller}}/{{action}}", pluginName),
    new { },
    new string[] { string.Format("{0}.Controllers", pluginName) });

ViewEngineвыглядит так: -

public class PluginRazorViewEngine : RazorViewEngine
{
    public PluginRazorViewEngine() : base()
    {
        ViewLocationFormats = new[]
        {
            "~/Plugin/%1/Views/{1}/{0}.cshtml",
            "~/Plugin/%1/Views/{1}/{0}.vbhtml",
            "~/Plugin/%1/Views/Shared/{0}.cshtml",
            "~/Plugin/%1/Views/Shared/{0}.vbhtml",
            "~/Views/{1}/{0}.cshtml",
            "~/Views/{1}/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };

(% 1 заменяется именем сборки)

и сборка регистрируется в библиотеке BoC следующим образом: -

BoC.Web.Mvc.PrecompiledViews.ApplicationPartRegistry.Register(assembly, string.Format("/Plugin/{0}/", pluginName));

Когда представление загружается из сборки плагина (в данном примере это «учетные записи»), представление найдено и отображается ОК.Но затем он ищет в этих местах _ViewStart: -

~/plugin/accounts/views/invoice/_viewstart.cshtml
~/plugin/accounts/views/invoice/_viewstart.vbhtml
~/plugin/accounts/views/_viewstart.cshtml
~/plugin/accounts/views/_viewstart.vbhtml
~/plugin/accounts/_viewstart.cshtml
~/plugin/accounts/_viewstart.vbhtml
~/plugin/_viewstart.cshtml
~/plugin/_viewstart.vbhtml
~/_viewstart.cshtml
~/_viewstart.vbhtml

Но он не выглядит в ~ / Views / Shared / _ViewStart.cshtml, где находится файл.

I 'я пытался изменить все форматы расположения в моем ViewEngine (AreaMasterLocationFormats, AreaPartialViewLocationFormats, AreaViewLocationFormats, MasterLocationFormats, PartialViewLocationFormats и ViewLocationFormats), но ни один из них, кажется, не имеет значения.

Я посмотрел вокруг, и кажется, что System.Web.WebPages.StartPage.GetStartPage отвечает за поиск и возврат стартовой страницы в представлении, но я не могу найти никакой информации о том, как контролировать, где она выглядит.

I 'мы пытались переместить _ViewStart.cshtml в ~ / _ViewStart.cshtml (одно из мест, где он выглядит), однако я сразу же получаю:жить под / Views

Можно ли изменить, где MVC ищет _ViewStart?

Imp библиотеки BoCиспользует свой собственный IView и вызывает следующее: -

startPage = this.StartPageLookup(page, VirtualPathFactoryManagerViewEngine.ViewStartFileName, this.ViewStartFileExtensions);

Но в этом случае ViewStartFileName - это просто "_ViewStart", а ViewStartFileExtensions - это просто cshtml и vbhtml ... ничего, что могло бы контролировать, где MVC должен искатьфайл.

Ответы [ 2 ]

1 голос
/ 09 февраля 2012

Идея ... (как, в, не попробовал это. Будет ли это работать? Нет идеи)

Может быть, посмотрите на наследование от RazorView (или полностью замените его, учитывая, что, как мы увидим, вы будете переписывать один метод, который является основной частью класса).

RazorView - это то, где StartPage.GetStartPage вводится путем присвоения его свойству StartPageLookup:

// In RazorView constructor:
StartPageLookup = StartPage.GetStartPage;

К сожалению, это свойство делегата является внутренним, поэтому вы не можете просто перезаписать его в конструкторе вашего производного класса. Однако вы можете переопределить RazorView.RenderView, где используется (исходный код MVC3, много строк удалено, добавлены разрывы строк):

protected override void RenderView(ViewContext viewContext, TextWriter writer, 
   object instance) 
{
  // [SNIP]

  WebPageRenderingBase startPage = null;
  if (RunViewStartPages) {
     // HERE IT IS:
     startPage = StartPageLookup(
        webViewPage, 
        RazorViewEngine.ViewStartFileName, 
        ViewStartFileExtensions
     );
  }
  webViewPage.ExecutePageHierarchy(
     new WebPageContext(
        context: viewContext.HttpContext, 
        page: null, 
        model: null),
     writer, startPage);
}

Замените этот вызов StartPageLookup своим собственным поиском, затем замените результат CreateView и CreatePartialView в вашем PluginRazorViewEngine на ваш новый PluginRazorView класс.

1 голос
/ 09 февраля 2012

Итак, чтобы ответить на мой собственный вопрос ... кажется, нет, вы не можете изменить, где MVC ищет _ViewStart ...

Глядя на источник System.Web.WebPages.StartPage.GetStartPage (который я получил от здесь ) Я вижу, что он только проходит путь от вызывающей страницы до самого корня, и, похоже, нет никакого способа контролировать это поведение.(т. е. он жестко запрограммирован в System.Web.WebPages.StartPage)

При нормальных обстоятельствах (т. е. стандартная компоновка MVC3) все будет в порядке ... все представления располагаются в / Views, как и основной _ViewStartфайл, который будет оценен, когда GetStartPage достигнет его.

Итак, в основном я нарушил эту функцию, переместив мои представления из иерархии папок / Views.

Полагаю, это означаетЯ могу либо переместить свой файл _ViewStart в место, где он будет найден (что нарушает мою намеченную цель иметь общий _ViewStart для всех моих плагинов), либо поработать над некоторым способом переписать / переопределить каталогвыполнение запросов на _ViewStart в этой иерархии в правильный файл в / Views / Shared / _ViewStart (что не сразу для меня очевидно).

Интересно то, что код MVC3 будет искать _ViewStart в /который, основываясь на том, что я прочитал, не будет работать, что приведет к ошибке «Невозможно привести объект типа« ASP. Page _ViewStart_cshtml »к типу« System.Web.WebPages.StartPage '»(хотя я подозреваю, что это просто потому, что в файле по умолчанию /web.config нет необходимого для правильного анализа файла, в то время как /Views/web.config это делает)

...