9

ASP.NET MVC 中的“RenderPartial()”方法提供了非常低级别的功能。它不提供,也不试图提供真正的“子控制器”模型*。

我有越来越多的控件通过“RenderPartial()”呈现。它们分为 3 个主要类别:

1) 作为使用该页面模型的特定页面的直接后代的控件

2) 作为特定页面的直接后代的控件,这些控件使用该页面的模型和 某种类型的附加键。想想“DataRepeater”的实现。

3) 代表与其出现的页面无关的功能的控件。这可以是任何东西,从横幅旋转器到反馈表、商店定位器、邮件列表注册。关键是它不在乎放在哪个页面上。

由于ViewData模型的工作方式,每个请求只存在一个模型对象——也就是说,子控件需要的任何东西都必须存在于页面模型中。

最终,MVC 团队将有望推出真正的“子控制器”模型,但在那之前,我只是在主页面模型中添加子控件也需要的任何内容。

在上述 (3) 的情况下,这意味着我的“ProductModel”模型可能必须包含“MailingListSignup”模型的字段。显然这并不理想,但我已经接受了与当前框架的最佳折衷方案 - 并且最不可能“关闭任何门”到未来的子控制器模型。

控制器应该负责获取模型的数据,因为模型实际上应该只是一个不知道从哪里获取数据的愚蠢数据结构。但我不希望控制器必须在几个不同的地方创建模型。

我已经开始做的是创建一个工厂来为我创建模型。这个工厂被控制器调用(模型不知道工厂)。

public static class JoinMailingListModelFactory {

        public static JoinMailingListModel CreateJoinMailingListModel() {

            return new JoinMailingListModel()
            {
                MailingLists = MailingListCache.GetPartnerMailingLists();
            };
        }
    }   

所以我的实际问题是其他有同样问题的人实际上是如何创建模型的。未来与新 MVC 功能兼容的最佳方法是什么?


  • 注意:有一些问题RenderAction()我不会在这里讨论——尤其是它只在 MVCContrib 中,而不是在 ASP.NET-MVC 的 RTM 版本中。其他问题引起了足够多的问题,我选择不使用它。所以让我们暂时假装它只RenderPartial()存在——或者至少那是我决定使用的。
4

4 回答 4

5

与其添加诸如MailingListSignup属性之类的东西,不如ProductModel将两者封装在一个类中的同一级别,ProductViewModel如下所示:

public class ProductViewModel() {
    public ProductModel productModel;
    public MailingListSignup signup;
}

然后让你的视图被强类型化到ProductViewModel类中。您可以ProductModel通过调用访问Model.productModel,也可以使用 访问注册类Model.signup

这是对 Fowler 的“演示模型”( http://martinfowler.com/eaaDev/PresentationModel.html ) 的松散解释,但我已经看到一些 Microsoft 开发人员使用它,例如 Rob Conery 和 Stephen Walther。

于 2009-03-16T05:47:49.847 回答
2

我在这种情况下看到的一种方法是使用动作过滤器来填充部分视图的数据 - 即 subclass ActionFilterAttribute。在 中OnActionExecuting,将数据添加到 ViewData。然后,您只需使用过滤器装饰使用该部分视图的不同操作。

于 2009-03-13T05:58:23.377 回答
1

我使用了一个 RenderPartial 重载,让您指定一个新的 ViewData 和 Model:

渲染部分代码

如果你看MVC源代码的上一个链接,以及下面的(寻找RenderPartialInternal方法):

RenderPartial内部代码

您可以看到,如果基本上复制您传递的视图数据,则创建一个新字典并设置要在控件中使用的模型。所以页面可以有一个Model,但是再传递一个不同的Model给子控件。

如果子控件没有直接从主视图模型中引用,您可以使用 Marc Gravell 提到的技巧来添加您的自定义逻辑。

于 2009-03-13T20:19:13.120 回答
0

我尝试的一种方法是使用带有接口的强类型局部视图。在大多数情况下,聚合 ViewModel 是更好的方法,但我仍然想分享这一点。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>

Viewmodel 实现接口

 public class ProductViewModel:IMailingListSignup

这一点都不完美,但解决了一些问题:您仍然可以轻松地将属性从路由映射到模型。我不确定是否可以将路由参数映射到 MailingListSignup 的属性,否则。

您仍然有填充模型的问题。如果还不晚,我更喜欢在 OnActionExecuted 中进行。我看不到如何在 OnActionExecuting 中填充模型。

于 2009-07-07T21:34:41.967 回答