3

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.

Brandon Linton
  • 4,273
  • 5
  • 39
  • 61

1 Answers1

5
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
  • 32,325
  • 3
  • 84
  • 87
  • +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 Apr 12 '10 at 13:30
  • 2
    Add the FirstName property to the Model itself, so you would bind with x => x.FirstName instead of x => x.Data.FirstName. – mxmissile Apr 12 '10 at 13:37
  • 1
    @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 Apr 12 '10 at 13:56
  • 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 Apr 13 '10 at 20:39