MVC3 - 编译的Razor视图找不到_ViewStart

Ale*_*eks 5 plugins razor asp.net-mvc-3

我在单独的类库中使用编译的Razor视图作为MVC3的一种插件系统.

我接着克里斯·范·德斯蒂德导向这里,只有主要偏离的部分有关添加引用,因为我装我的组装件在运行时.

因为我在运行时加载程序集,所以我没有在BoC库中使用VirtualPathProviderViewEngine,而是基于RazorViewEngine实现了我自己的ViewEngine.它的工作原理是在CreateView中重写viewPath以插入适当的命名空间,以便可以解析视图.

到目前为止一切都很好......我可以加载不同的模块,如果它们共享相同的名称,它们的控制器不会发生冲突.

我现在唯一的问题是,对于编译视图,不会调用_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) });
Run Code Online (Sandbox Code Playgroud)

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"
        };
Run Code Online (Sandbox Code Playgroud)

(%1被替换为程序集的名称)

并且汇编在BoC库中注册如下: -

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

从插件程序集加载视图时(在此示例中为"accounts"),查找并显示视图.但是它会在这些位置查找_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
Run Code Online (Sandbox Code Playgroud)

但它没有查看文件所在的〜/ Views/Shared/_ViewStart.cshtml.

我试过改变我的ViewEngine中的所有位置格式(AreaMasterLocationFormats,AreaPartialViewLocationFormats,AreaViewLocationFormats,MasterLocationFormats,PartialViewLocationFormats和ViewLocationFormats),但它们似乎没有任何区别.

我环顾四周,似乎System.Web.WebPages.StartPage.GetStartPage负责查找并返回视图中的起始页面,但我找不到任何有关如何控制它的外观的信息.

我已经尝试将_ViewStart.cshtml移动到〜/ _ViewStart.cshtml(它看起来的地方之一)但是我马上得到: -

Unable to cast object of type 'ASP._Page__ViewStart_cshtml' to type 'System.Web.WebPages.StartPage'.
Run Code Online (Sandbox Code Playgroud)

根据我所读到的,是因为_ViewStart需要生活在/ Views下

我可以修改MVC查找_ViewStart的位置吗?

BoC库实现了它自己的IView,并调用以下内容:

startPage = this.StartPageLookup(page, VirtualPathFactoryManagerViewEngine.ViewStartFileName, this.ViewStartFileExtensions);
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,ViewStartFileName只是"_ViewStart"而ViewStartFileExtensions只是cshtml和vbhtml ......没有什么可以控制MVC搜索文件的位置.

Jim*_*iTh 1

一个想法......(例如,还没有尝试过。它会起作用吗?不知道)

也许看看继承RazorView(或完全替换它,考虑到 - 正如我们将看到的 - 您将重写作为类的大部分的一个方法)。

RazorViewStartPage.GetStartPage通过将其分配给StartPageLookup属性来引入的:

// In RazorView constructor:
StartPageLookup = StartPage.GetStartPage;
Run Code Online (Sandbox Code Playgroud)

不幸的是,该委托属性是内部的,因此您不能在派生类的构造函数中覆盖它。但是,您可以覆盖它的使用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);
}
Run Code Online (Sandbox Code Playgroud)

CreateView将 StartPageLookup 调用替换为您自己的查找,然后将和的结果替换为CreatePartialViewPluginRazorViewEngine的新PluginRazorView类。