views:

1237

answers:

1

So I'm looking at moving from MVC 1.0 to MVC 2.0 RTM. One of the conventions I'd like to start following is using the strongly-typed HTML helpers for generating controls like text boxes.

However, it looks like it won't be an easy jump. I tried migrating my first form, replacing lines like this:

<%= Html.TextBox("FirstName", Model.Data.FirstName, new {maxlength = 30}) %>

...for lines like this:

<%= Html.TextBoxFor(x => x.Data.FirstName, new {maxlength = 30}) %>

Previously, this would map into its appropriate view model on a POST, using the following method signature:

[HttpPost]
public ActionResult Registration(AccountViewInfo viewInfo)

Instead, it currently gets an empty object back. I believe the disconnect is in the fact that we pass the view model into a larger aggregate object that has some page metadata and other fun stuff along with it (hence x.Data.FirstName instead of x.FirstName).

So my question is: what is the best way to use the strongly-typed helpers while still allowing the MVC framework to appropriately cast the form collection to my view-model as it does in the original line? Is there any way to do it without changing the aggregate type we pass to the view?

Thanks!

UPDATE: So the bind attribute worked well, but I didn't love how I had to apply it to essentially every posted view model. I ended up changing the inheritance hierarchy such that all of our view models inherit from a base class that contains page content and other meta data, as opposed to being an aggregate property named Data.

+4  A: 
public ActionResult Registration([Bind(Prefix = "data")] AccountViewInfo viewInfo);

This tells the binder that it should expect all values to start with data, so it will look for data.FirstName, etc.

Levi
+1 since that definitely will work. Although I'm curious if there are any ways to enforce this more globally? I'd rather not add the `[Bind]` attribute in every POST manually if I can avoid it. It'd be awesome if I could enforce it in a base controller or some sort of class-level attribute that checked for non form-collection reference types.
Brandon Linton
Add the FirstName property to the Model itself, so you would bind with x => x.FirstName instead of x => x.Data.FirstName.
mxmissile
@mxmissile that would fix it, but the actual `Model` is a strongly typed container, where the strong type is applied to the `Data` attribute. So from an architectural standpoint that wouldn't work for me in this case.
Brandon Linton
Marking as resolved since it's ended up being the fix we're going with for now. If anyone has any ways to make this more generic, please add it. Thanks!
Brandon Linton