ASP.Net MVC和RenderPartial带相对路径

11

我一直在尝试 ASP.NET MVC 并且有一个问题,或者可能是我做错了什么。只是在开发一个普通的网站来拓宽自己的技能。抱歉这个问题并不简短。

好的,这是场景:当用户访问home/index时,页面应该显示产品列表和文章列表。文件布局如下(DAL 是我的数据访问层):

Controllers
    Home
        Index
Views Home Index 继承自 ViewPage Product List 继承自 ViewUserControl<IEnumerable<DAL.Product>> Single 继承自 ViewUserControl<DAL.Product> Article List 继承自 ViewUserControl<IEnumerable<DAL.Article>> Single 继承自 ViewUserControl<DAL.Article>
Translated version:

我在尝试使用ASP.NET MVC,有一个问题,或者可能是我做错了什么。我正在制作一个简单的网站以提高自己的技能水平。很抱歉这个问题并不简洁明了。

下面是场景:当用户访问home/index时,页面应该显示产品列表和文章列表。文件布局如下(DAL代表数据访问层):

控制器
    Home
        Index
视图 Home Index 继承自ViewPage Product List 继承自ViewUserControl<IEnumerable<DAL.Product>> Single 继承自ViewUserControl<DAL.Product> Article List 继承自ViewUserControl<IEnumerable<DAL.Article>> Single 继承自ViewUserControl<DAL.Article>
Controllers.HomeController.Index produces a View whose ViewData contains two entries, a IEnumerable<DAL.Product> and a IEnumerable<DAL.Article>.

View.Home.Index will use those view entries to call:
Html.RenderPartial("~/Views/Product/List.ascx", ViewData["ProductList"])
and Html.RenderPartial("~/Views/Article/List.ascx", ViewData["ArticleList"])

View.Product.List will call
foreach(Product product in View.Model)
    Html.RenderPartial("Single", product);

View.Article.List does something similar to View.Product.List

然而,这种方法是失败的。虽然这个方法在我看来是有意义的,但或许有更多经验的MVC平台用户能够识别出更好的方法。

上述代码在View.Product.List内部产生了一个错误。调用Html.RenderPartial("Single",...)时会提示"Single"视图未被找到。该错误信息如下:

The partial view 'Single' could not be found. The following locations were searched:
~/Views/Home/Single.aspx
~/Views/Home/Single.ascx
~/Views/Shared/Single.aspx
~/Views/Shared/Single.ascx

由于我是从Product视图中调用RenderAction(),我期望运行时会在Views\Product中寻找"Single"视图。然而,事实上查找的相对位置是与调用原始视图的控制器(/Controller/Home 调用 /Views/Product)相关的,而不是当前视图。

所以,我可以通过更改Views\Product来修复这个问题,使其如下:

View.Product.List will call
foreach(Product product in View.Model)
    Html.RenderPartial(<b>"~/Views/Product/Single.ascx"</b>, product);

取代

View.Product.List will call
foreach(Product product in View.Model)
    Html.RenderPartial(<b>"Single"</b>, product);

这个修复方法可行,但是我不明白为什么需要指定完整的视图路径。按照我的理解,相对名称应该相对于当前视图的路径进行解释,而不是原始控制器的视图路径。除了在典型情况下它们相同的情况下之外,我无法想象出任何有用的情况,在这种情况下,将名称解释为相对于控制器视图而不是当前视图是有用的。

这个时候我应该加上一个问号?以强调这实际上是一个问题。


刚好在寻找相关内容时偶然发现了这篇文章(我意识到它已经超过6个月了)。但是你提到了使用RenderAction(),然而你所有的例子都使用了RenderPartial(),这是一个笔误吗?我认为RenderAction(而不是RenderPartial)应该在这种情况下起作用? - Simon Fox
3个回答

5
因为我在Product视图中调用RenderAction()方法,所以我不明白为什么需要指定完整路径的视图。相对名称应该相对于当前视图路径而不是原始控制器的视图路径才有意义。我认为你误解了"执行位置"这个术语,路径不是相对于你的视图,甚至不是相对于你的"控制器视图"。它们是相对于请求URL的,请求URL定义了一个控制器上下文。如果你花一点时间在反编译器中查看URL和路由的解析方式,我想这一切都会在你的脑海中变得清晰起来。

这种行为是有意义的,但我不明白为什么会设计成这样。我认为视图中的代码不应该需要知道它被调用的路径。 - Frank Schwieterman

4

[编辑:

我在想,你有两种情况:

  • 首页控制器是唯一引用产品/文章列表用户控件的控制器
  • 用户控件被多个控制器共享

在第一种情况下,视图用户控件真正属于首页控制器,将它们放置在首页控制器文件夹中是有意义的。在第二种情况下,将它们放置在共享文件夹中是有意义的,因为它们将被多个控制器共享。

无论哪种情况,也许你可以将它们放在一个子文件夹中。例如Views/Home/Products,然后尝试RendarPartial("Product/Single"),看看会发生什么?我不知道它是否会尝试解析为:Home/Product/Single,然后Shared/Product/Single或者不会。如果子文件夹可行,似乎允许对产品和文章进行逻辑分离,同时显示它们仍然是首页控制器的成员或所有控制器共享的成员。

]

查看Steve Sanderson的博客文章:

http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/

你所做的并没有错,但似乎违反了View/Controller文件夹名称的约定。话虽如此,定义与控制器无关的视图用户控件并将它们嵌套起来是有意义的。所以我不知道该怎么办!
无论如何,这个链接描述的只是一种方法,即使用RenderPartialRequest而不是RenderPartial来呈现使用控件,它定义了一个RenderPartialRequest方法,该方法呈现控制器操作的返回值(在您的情况下为用户控件)。因此,您可以添加Product和Articles控制器,并添加返回您的用户控件的Action List,然后从Home/Index视图调用这两个操作。这对我来说更直观,但这只是我的看法。
他还提到了MVC Contrib中的子控制器,我相当确定ASP.NET MVC发布版中也会像这样有类似的功能需求。

RenderPartial("Product/Single") 可以在 Product 视图文件夹的子文件夹中使用。我刚刚使用了这种技术来处理一些部分视图,我希望将它们与控制器相关的 ASPX/ASCX 文件分开放置。 - RichardOD

2
从查看MVCStoreFront示例,以下是他们用于调用RenderPartial的结构:
Views
    Shared
        ProductSingle
        ProductList
        ArticleSingle
        ArticleList

然后通过以下方式呈现它们:
<% Html.RenderPartial("ProductSingle", ViewData["ProductList"]); %>
<% Html.RenderPartial("ProductList", product); %>
<% Html.RenderPartial("ArticleSingle", article); %>
<% Html.RenderPartial("ArticleList", ViewData["ArticleList"]); %>

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