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

时间:2012-02-08 10:27:37

标签: asp.net-mvc-3 plugins razor

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

我已经按照Chris Van De Steed here的指南进行了操作,并且主要是关于添加引用的部分,因为我在运行时加载了我的程序集。

因为我在运行时加载程序集,所以我没有在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) });

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

从插件程序集加载视图时(在此示例中为“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

但它没有查看文件所在的〜/ 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'.

根据我所读到的,是因为_ViewStart需要存在于/ Views

之下

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

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

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

但在这种情况下,ViewStartFileName只是“_ViewStart”而ViewStartFileExtensions只是cshtml和vbhtml ......没有任何东西可以控制MVC搜索文件的位置。

2 个答案:

答案 0 :(得分:1)

所以,回答我自己的问题......似乎没有,你无法修改MVC寻找_ViewStart的位置......

查看System.Web.WebPages.StartPage.GetStartPage的源代码(我从here获得)我可以看到它只遍历从调用页面一直到根目录的路径,并且似乎没有任何方法可以控制这种行为(即它在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确实)

答案 1 :(得分:1)

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

也许看看从RazorView继承(或者完全替换它,考虑 - 正如我们将看到的那样 - 你将重写一个方法,这是该类的大部分)。

RazorView是通过将StartPage.GetStartPage属性分配给StartPageLookup来引入// In RazorView constructor: StartPageLookup = StartPage.GetStartPage; 的地方:

RazorView.RenderView

不幸的是,该委托属性是内部的,因此您不能仅在派生类的构造函数中覆盖它。但是,您可以覆盖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); } ,这是使用的地方(MVC3源代码,删除了大量行,我添加了换行符):

CreateView

将StartPageLookup调用替换为您自己的查找,然后将CreatePartialView中的PluginRazorViewEnginePluginRazorView的结果替换为新的{{1}}类。