在ASP.NET MVC中,我如何使部分视图对所有控制器可用?

3
在ASP.NET MVC中,我如何使部分视图对所有控制器可用?我想创建整个站点通用的导航,但是当我将Html.Action放入我的主页面时,它只适用于与1个控制器相关联的视图。
现在,我有一个控制器操作定义如下:
    // GET: GetCategoriesPartial
    [ChildActionOnly]
    public ActionResult GetCategoriesPartial()
    {
        var category = CategoriesDataContext.GetCategories();
        return PartialView(category);
    }

我已经按照以下方式创建了我的局部视图

<%@ Import Namespace="wopr.Models" %>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<ul>
<%
    foreach (var cat in Model as IEnumerable<Category>) {
        %>
        <li><a href="/categories/Details/<%=cat.catID%>"><%=cat.catName%></a></li>
        <%
    }

%>
</ul>

我的母版页长这样:

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link type="text/css" rel="Stylesheet" href="/Content/Site.css" />
</head>
<body>
    <div class="wrap-all">
    <div style="text-align:right;">
        <a href="/">Home</a> | 
        <a href="/games/">Games</a> | 
        <a href="/games/Index2/1">Games <em>(paginated)</em></a> | 
        <a href="/categories/">Categories</a> | 
        <a href="/upload/">Upload</a>
    </div>
        <asp:ContentPlaceHolder ID="MainContent" runat="server">

        </asp:ContentPlaceHolder>


        <!--This errors on any non-CategoryController page.-->
            <%= Html.Action("GetCategoriesPartial")%>
        <!---->

    </div>
</body>
</html>

只要我查看由CategoriesController处理的内容,这段代码就能正常工作。如果我查看其他控制器处理的视图,则会出现以下异常:
System.Web.HttpException:在控制器‘wopr.Controllers.GamesController’上未找到公共操作方法“GetCategoriesPartial”。
我该如何使此部分视图对网站的所有控制器都可用?
感谢任何帮助。 Quakkels

把它放在共享文件夹里? - dotjoe
顺便提一下,如果您想在整个网站上共享菜单,应该考虑将其直接放入主页面中,而不是使用“RenderAction”进行包含。 - Roman
我将其放在主页面中。这就是为什么我需要使子操作对所有控制器都可用的原因。 - Quakkels
我的意思是菜单是静态内容还是根据登录用户等动态变化的内容? - Roman
3个回答

3
将其放置在 views\shared 文件夹中。
然而,从您的错误消息来看,似乎还发生了其他事情。您不能使用 <%=Html.Action%> 来呈现视图。您应该使用 <%=Html.RenderPartial("ViewName")%>

请原谅我的新手方式 :-) 这怎么运作呢?我认为视图中不应执行任何逻辑。或者将部分视图操作的定义放在那里可以吗? - Quakkels
你所包含的不是逻辑,而是标记。用户控件本质上只是一种紧凑的视图。 - James
Renderpartial不需要控制器/操作。正如Pharabus所述,它会查找当前控制器文件夹中的视图,然后在共享文件夹中查找。您可以将第二个参数作为部分视图中的模型传递(可通过控制器和主页面作为viewdata传递)。 - Ropstah
我使用<%=Html.Action,因为Phill Haack http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx 推荐这种方式。 - Quakkels
@James:我不明白你想说什么? - Ropstah
显示剩余5条评论

2

MVC2现在可以直接在视图中呈现一个操作。如果不是从同一个控制器呈现,您需要指定操作所在的控制器。如果您以这种方式包含它,则您的部分视图可以位于控制器的视图文件夹中(而不是共享的)。请注意,它不会获取当前操作的ViewData - 只有您调用的操作设置的ViewData。

<% Html.RenderAction( "GetCategoriesPartial", "Category" ) %>

或者

<%= Html.Action( "GetCategoriesPartial", "Category" ) %>

我真的应该继续我的生活了..(读作:转移到MVC2 :P)。那样我就能得到被接受的答案! - Ropstah
@ropstah - 我知道你的意思 - 我现在正在回去清理一个MVC1应用程序中的许多垃圾,当我做它时看起来很好,但现在MVC2有更强大的结构,看起来像是由一个5岁的孩子编写的。公平地说(对于这个平台),其中很多也反映了我最初学习时的知识不足。"谁是写这些东西的白痴,哎呀,是我..." - tvanfosson
我几年前就遇到过这个问题,但一个月前我又“亲身”遇到了它:VB 缺乏 lambda 构造! :) - Ropstah

1

仅补充ropstah的回复,asp.net-mvc 的约定是控制器首先查找与自身同名(不包括控制器部分)的文件夹,如果没有找到,则在 shared 文件夹下查找视图。


我正在打这个确切的回答,你比我更快! +1 - James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接