ASP.NET MVC 中的 ModelFactory 解决“RenderPartial”问题 问题
ASP.NET MVC 中的“RenderPartial()”方法提供非常低级别的功能。 它不提供,也不试图提供真正的“子控制器”模型*。
我有越来越多的控件通过“RenderPartial()”呈现。 它们分为 3 个主要类别:
1) 直接控制 特定页面的后代 使用该页面的模型
2) 直接控制 特定页面的后代 使用该页面的模型 某种类型的附加密钥。 思考实施 “数据中继器”。
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()
存在 - 或者至少我决定使用它。
The 'RenderPartial()' method in ASP.NET MVC offeres a very low level of functionality. It does not provide, nor attempt to provide a true 'sub-controller' model *.
I have an increasing number of controls being rendered via 'RenderPartial()'. They fall into 3 main categories :
1) Controls that are direct
descendants of a specific page that
use that page's model2) Controls that are direct
descendants of a specific page that
use that page's model with an
additional key of some type.
Think implementation of
'DataRepeater'.3) Controls that represent unrelated
functionality to the page they appear
on. This could be anything from a
banner rotator, to a feedback form,
store locator, mailing list signup.
The key point being it doesn't care
what page it is put on.
Because of the way the ViewData
model works there only exists one model object per request - thats to say anything the subcontrols need must be present in the page model.
Ultimately the MVC team will hopefully come out with a true 'subcontroller' model, but until then I'm just adding anything to the main page model that the child controls also need.
In the case of (3) above this means my model for 'ProductModel' may have to contain a field for 'MailingListSignup' model. Obviously that is not ideal, but i've accepted this at the best compromise with the current framework - and least likely to 'close any doors' to a future subcontroller model.
The controller should be responsible for getting the data for a model because the model should really just be a dumb data structure that doesn't know where it gets its data from. But I don't want the controller to have to create the model in several different places.
What I have begun doing is creating a factory to create me the model. This factory is called by the controller (the model doesn't know about the factory).
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
So my actual question is how are other people with this same issue actually creating the models. What is going to be the best approach for future compatibility with new MVC features?
- NB: There are issues with
RenderAction()
that I won't go into here - not least that its only in MVCContrib and not going to be in the RTM version of ASP.NET-MVC. Other issues caused sufficent problems that I elected not to use it. So lets pretend for now that onlyRenderPartial()
exists - or at least that thats what I've decided to use.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不要添加诸如
MailingListSignup
之类的内容作为ProductModel
的属性,而是将两者封装在同一级别的类中,例如ProductViewModel
,如下所示:让您的视图成为
ProductViewModel
类的强类型。 您可以通过调用Model.productModel
访问ProductModel
,并且可以使用Model.signup
访问注册类。这是对 Fowler 的“演示模型”的宽松解释 (http://martinfowler.com/eaaDev/PresentationModel。 html),但我见过一些 Microsoft 开发人员使用它,例如 Rob Conery 和 Stephen Walther。
Instead of adding things like
MailingListSignup
as a property of yourProductModel
, encapsulate both at the same level in a class likeProductViewModel
that looks like:Then get your View to be strongly-typed to the
ProductViewModel
class. You can access theProductModel
by callingModel.productModel
, and you can access the signup class usingModel.signup
.This is a loose interpretation of Fowler's 'Presentation Model' (http://martinfowler.com/eaaDev/PresentationModel.html), but I've seen it used by some Microsoft devs, such as Rob Conery and Stephen Walther.
对于这种情况,我见过的一种方法是使用操作过滤器来填充部分视图的数据 - 即子类
ActionFilterAttribute
。 在OnActionExecuting
中,将数据添加到ViewData中。 然后,您只需用过滤器装饰使用该部分视图的不同操作即可。One approach I've seen for this scenario is to use an action-filter to populate the data for the partial view - i.e. subclass
ActionFilterAttribute
. In theOnActionExecuting
, add the data into the ViewData. Then you just have to decorate the different actions that use that partial view with the filter.我使用了 RenderPartial 重载,让您指定新的 ViewData 和模型:
RenderPartial 代码
如果您查看 MVC 源代码的上一个链接,以及以下链接(查找 RenderPartialInternal 方法):
RenderPartialInternal 代码
您可以看到,如果基本上复制您传递的视图数据,创建一个新的字典并设置要在控件中使用的模型。 因此页面可以有一个模型,但然后将不同的模型传递给子控件。
如果子控件不是直接从主视图模型引用的,您可以使用 Marc Gravell 提到的技巧来添加自定义逻辑。
There's a RenderPartial overload I use that let's you specify a new ViewData and Model:
RenderPartial code
If you look at the previous link of the MVC source code, as well as the following (look for RenderPartialInternal method):
RenderPartialInternal code
you can see that if basically copies the viewdata you pass creating a new Dictionary and sets the Model to be used in the control. So the page can have a Model, but then pass a different Model to the sub-control.
If the sub-controls aren't referred directly from the main View Model, you could do the trick Marc Gravell mentions to add your custom logic.
我尝试的一种方法是使用带有接口的强类型部分视图。 在大多数情况下,聚合 ViewModel 是更好的方法,但我仍然想分享这一点。
Viewmodel 实现的接口
根本不完美,但解决了一些问题:您仍然可以轻松地将属性从路由映射到模型。 我不确定您是否可以将路由参数映射到 MailingListSignup 的属性。
您仍然遇到填充模型的问题。 如果还不算太晚,我更喜欢在 OnActionExecuted 中执行此操作。 我不明白如何在 OnActionExecuting 中填充模型。
One method I tried was to use a strongly typed partial view with an interface. In most situations an agregated ViewModel is the better way, but I still want to share this.
The Viewmodel implements the interface
Thats not perfect at all but solves some issues: You can still easily map properties from your route to the model. I am not shure if you can have a route parameter map to the properties of MailingListSignup otherwise.
You still have the problem of filling the Model. If its not to late I prefer to do it in OnActionExecuted. I dont see how you can fill a Model in OnActionExecuting.