ASP.Net MVC 2:使用视图模型会破坏我的模型绑定
我想这是一个关于框架如何愉快地完成你所需要的 95% 的事情,但随后却对最后 5% 皱眉不满的故事;通知您,如果您想参与非标准的 Malarky,那是您自己的事,非常感谢您,如果您决定返回做它擅长的事情,它就会在这里。一般来说,最后的百分之五将不可避免地包含某些版本的必备功能。
我有一个更新数据对象的强类型视图。我使用了惯用的 MVC2 助手,例如 Html.TextBoxFor(model = > model.Name)
。我已将编辑器模板用于嵌套对象。 (我的后端是 Mongo 文档的集合,因此我需要表示复杂类型)。
然后我需要一个下拉菜单。事实证明,下拉菜单有点挑剔;没问题,我将创建一个视图模型,而不是直接传入 item
:
class itemViewModel
{
...
public Item item { get; set; }
public IEnumerable<SelectListItem> dropdown { get; set; }
}
public ActionResult()
{
return View("Update", new itemViewModel(item, dropdown))
}
...工作正常,下拉列表会填充。但!我的观点需要更新:
Html.TextBoxFor(model => model.Name) ->
Html.TextBoxFor(model => model.item.Name)
太好了,问题解决了。糟糕,现在我的模型绑定不起作用。我调试并查看 Request.Form
值:哦。 item.Name
而不是 Name
。有道理。我告诉我的 Update 视图期待一个 itemViewModel
,并且绑定有效。
哦等等,不,事实并非如此。因为我有使用编辑器的嵌套对象。它们是强类型的,并且不知道接收到的模型实际上是视图模型的属性。因此,他们仍然输出 Address.City
而不是 item.Address.City
,并且绑定失败。
我可以想到几种解决方法:
- 编写专门的自定义模型绑定器
- 将整个该死的表单放入其自己的类型编辑器中,这样它就可以在不知道它是属性的情况下获取
item
模型 - 杀死视图模型并使用
ViewData
字典 - 退出使用
HtmlHelpers
并手写整个表单 - 编写我自己的
HtmlHelper
扩展,该扩展将采用 lba 和 一个模型对象作为参数。 - 将每个标签/字段分组放入单独的编辑器模板中。
所有这些感觉要么是矫枉过正,要么是草率。视图模型似乎是一种干净、有用的方法。使用它们是否意味着我必须在其他领域马虎,或者在框架的相当大的块上重现微小的变化?在过去的三个月里,我自学了 C#(一个图形设计师在没有 CS 背景的情况下试图弄清楚静态类型到底是什么,这可能看起来很有趣)。我孤立地工作;没有人可以向其学习最佳实践。我觉得如果我不学习其中一些,我最终会变成一堆无法维护的粪便。因此,非常感谢您的意见。
I guess this is a story of how frameworks cheerfully do 95% of what you need, but then frown disapprovingly at that final five percent; inform you that if you want to participate in nonstandard malarky it's your own business, thank you very much, and it'll be here if you decide you want to return to doing things it's good at. Generally speaking it's inevitable that this final five percent will contain some version of a must-have feature.
I have a strongly-typed view which updates a data object. I've used idiomatic MVC2 helpers, eg Html.TextBoxFor(model = > model.Name)
. I've used Editor templates for nested objects. (My backend is a collection of Mongo documents, so I need to represent complex types).
Then I need a dropdown. It turns out dropdowns are a bit finicky; no problem, I'll make a viewmodel instead of passing in the item
directly:
class itemViewModel
{
...
public Item item { get; set; }
public IEnumerable<SelectListItem> dropdown { get; set; }
}
public ActionResult()
{
return View("Update", new itemViewModel(item, dropdown))
}
... that works fine, the dropdown populates. But! my view requires updating:
Html.TextBoxFor(model => model.Name) ->
Html.TextBoxFor(model => model.item.Name)
Great, problem solved. Oops, now my model binding doesn't work. I debug and look at the Request.Form
values: Oh. item.Name
instead of Name
. Makes sense. I tell my Update view to expect an itemViewModel
instead, and the binding works.
Oh wait, no it doesn't. Because I have nested objects that use editors. They are strongly typed and they don't know that the model they're receiving is actually a property of the viewmodel. So they're still spitting out Address.City
instead of item.Address.City
, and the binding fails.
I can think of several workarounds:
- Write specialized custom model binder
- Put the whole damn form into its own typed editor, so it gets the
item
model without knowing it's a property - Kill the viewmodel and hack the dropdown using the
ViewData
dictionary - Quit using the
HtmlHelpers
and hand-write the whole form - Write my own
HtmlHelper
extensions that will take a lamba and a model object as parameters. - Put every label/field grouping into an individual editor template.
All of these feel like either overkill or sloppiness. Viewmodels seem to be a clean, helpful approach. Does using them mean that I have to be sloppy in other areas, or reproduce minor variations on sizeable chunks of the framework? I taught myself C# over the last three months (a graphic designer trying to figure out what the hell static typing is with no CS background was probably pretty funny to watch). I work in isolation; there's no one to learn best practices from. I feel like if I don't learn some of them, I'll end up with an unmaintainable dung heap. So, your opinions are appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Daniel,首先我要说的是,我对您的努力以及对 .NET、C# 和 ASP.NET MVC 的大力支持表示赞赏。好吧,所以你很沮丧,我对此也有感触。这种事时不时地发生在我们所有人身上。
我应该让你知道,我不是 ASP.NET MVC 的粉丝(事实上,一点也不)(ASP.NET MVC 框架设计问题),因此我无法为您的问题提供解决方案。但我希望你看到你所处的情况:
你在一个迷宫里,你在某个地方拐错了一个弯,你正在深入迷宫,但你不会找到一条出路。所以你需要做的就是退回去,直到那个错误的转弯处,看看是否还有其他路线。因此,从你所处的位置开始,问自己“为什么”你所做的每一步/改变,然后一次退一步问为什么。这有道理吗?你最终会发现有其他替代方法来解决相同的(原始)问题。
Daniel, first off I should say that I commend you on your efforts and taking on .NET , C# and ASP.NET MVC all in one big bite. Ok, so you're frustrated and I relate to that. It's happens to all of us every now and then.
I should let you know that I'm not a fan (not in the least bit, in fact) of ASP.NET MVC (Problems with ASP.NET MVC Framework Design) and so I can't give you a worked out solution to your problem. But here is how I'd like you to see the situation you're in:
You're in a maze and you've made one wrong turn somewhere and you're going deeper into the maze but you're not going to find a way out. So what you need to do is back out till that wrong turn and see if there is another route. So starting from where you are, ask yourself, "why" for every step/change you've made and back up one step at a time asking why. does that make sense? you'll eventually get to a point where you have other alternative ways to tackle the same (original) problem.
叹。经过几个小时的谷歌搜索和黑暗中的一些镜头,似乎有一种令人难以置信的简单方法可以做到这一点,使用
Bind
属性:该属性似乎足够智能,可以访问复杂的类型。
我将留下这个作为对我自己无知的致敬,并希望其他一些不幸的 n00b 能比我更快找到答案。
Sigh. A couple more hours of Googling and a few shots in the dark, and it appears that there is an unbelievably straightforward way for doing this, using the
Bind
attribute:The attribute seems to be smart enough to reach into the complex types.
I will leave this as a tribute to my own ignorance, and in hopes that some other hapless n00b will find an answer quicker than I did.