在调用RenderAction时,在MVC视图上设置masterName会导致错误

时间:2011-03-03 02:06:22

标签: asp.net-mvc-3 master-pages viewengine renderaction

我有一个使用RenderAction调用View的Masterpage(site.master)。目前View返回“hello world”。

的Site.Master:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<html>
<head id="Head1" runat="server">
   <title><asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" /></title>
   <asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server" />
</head>

<body>
    <% Html.RenderAction("Test", "Charts"); %>

    <asp:ContentPlaceHolder ID="ContentPlaceHolder3" runat="server" >
      <p>site.master</p>
    </asp:ContentPlaceHolder>

    <asp:ContentPlaceHolder ID="ContentPlaceHolder4" runat="server" />  
</body>
</html>

Test.aspx文件:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

hello world!

ChartsController.cs:

public ActionResult Test()
{
    return View();
}

如果我更新View以显式传递Masterpage的名称,则在调用RenderAction时会出现错误。

ChartsController.cs:

public ActionResult Test()
{
    return View(null, "site");
}

错误:

内容控件必须是内容页面或引用母版页的嵌套母版页中的顶级控件。

Stack Trace:

[HttpException (0x80004005): Content controls have to be top-level controls in a content page or a nested master page that references a master page.]
   System.Web.UI.MasterPage.CreateMaster(TemplateControl owner, HttpContext context, VirtualPath masterPageFile, IDictionary contentTemplateCollection) +8857854
   System.Web.UI.Page.get_Master() +54
   System.Web.UI.Page.ApplyMasterPage() +15
   System.Web.UI.Page.PerformPreInit() +45
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +328

如何设置我希望视图使用的母版页?最终,我将使用自定义ViewEngine动态设置母版页(通过覆盖VirtualPathProviderViewEngine.FindView)。

if ( String.IsNullOrEmpty(masterName) ){ masterName = "site"; }

当我在ViewEngine中设置masterName属性然后从site.master调用RenderAction时,我得到的错误与在Action中设置masterName属性时的错误相同。

我正在使用:
Visual Studio 2010
MVC 3
IIS Express

已编辑:已添加完整的site.master标记

2 个答案:

答案 0 :(得分:0)

子类ViewPage<T>并覆盖OnPreInit()事件。在你的覆盖中,

protected override void OnPreInit(EventArgs e)
{
    this.MasterLocation = GetMasterLocation();
    base.OnPreInit(e);
}

GetMasterLocation()方法应该获取视图的文件名(以“~/”开头)。

错误来自CreateMaster中的MasterPage方法,抛出它的代码是:

if (masterPageFile == null)
{
    if ((contentTemplateCollection != null) && (contentTemplateCollection.Count > 0))
    {
        throw new HttpException(SR.GetString("Content_only_allowed_in_content_page"));
    }
    return null;
}

因此,MasterPage不存在且内容模板集合具有模板,因此页面抛出异常。按照上述说明将以编程方式设置母版页的位置(将其处理为虚拟路径,即变量masterPageFile

答案 1 :(得分:0)

我提出了一个解决方案,至少部分回答/理解了我的问题。

如果我是正确的,问题是我试图在没有/不需要母版页的视图上设置母版页。我认为结果是我设置了一个主页的路径,即使该主页存在,View也不期望它并且通过错误。

当我更新View以使用Masterpage时,我能够将Masterpage的名称直接传递给View而没有错误。

Test.aspx文件:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Charts.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    hello world!
</asp:Content>

我在自定义ViewEngine中解决此问题的方法是检查当前View是否为ChildAction。

if (String.IsNullOrEmpty(masterName) && !controllerContext.IsChildAction)
{
    masterName = "site";
}