asp.net mvc strongly typed helpers - should your render binding object be the same as your posting object?
i see that asp.net mvc 2 has strongly typed helped and looking initially at the way it works i think maybe i am doing something wrong in asp.net mvc 1 in terms of data binding to render the view and post back to the controller.
I often have different objects for rendering the view and posting back to the controller. is this wrong ?? It seems natural as when rendering the view you often have a viewmodel that has lists for dropdowns, etc. but for your posting you only want the properties that are needed to post back.
for example, on the way in for rendering, my viewmodel might look like this
public class PersonViewModel
{
public int Age;
public string FIrst;
public JobCategory[] JobCategories;
public Sport[] Sports;
public int NumberOfChildren;
}
in this case, jobCategories and Sports is going to be used to populate a dropdown box. NumberOfchildren is going to just be html put in and i dont want it editable. When i want to post i only want to pass back a slim object with just the posted properties so i have another object
public class PersonUpdater
{
public int Age;
public string FIrst;
public int JobCategoryId;
}
these are the only properties that i need to pass back so my controller will look like this:
开发者_如何学运维 public ActionResult Update(PersonUpdater personUpdater)
{
_repository.UpdateModel(personUpdater).
}
so, given the above, assuming the strongly typed helper methods (below) seem useful for the way in but then may cause issues on posting back to the server if you are referrring to different properties.
http://weblogs.asp.net/scottgu/archive/2010/01/10/asp-net-mvc-2-strongly-typed-html-helpers.aspx
any thoughts?
Real problem is - current accepted approach ignores SRP for view models a bit - edit form acts as input and output simultaneously.
People haven't accepted yet dividing view model
into, as i call them, input view model
and output view model
(for many - even creating view model
layer is too much). Therefore - Mvc2 currently lacks support for this (you aren't supposed to have strongly typed view that's not input and output at the same time) mainly because of vagueness and lack of broadly accepted approaches.
But i do think that there's a gain (ok... it's actually a trade off) in going deeper and separating view model
into 2 of them. And i won't be surprised if this idea will evolve and eventually become widely accepted.
Actually - current approach even has a name - Thunderdome principle. And if guys like Jeremy D. Miller says this is correct, community won't bother and won't search for anything else.
From practical point of view - some of the issues you can mitigate through providing correct metadata (you might want to check out fluent model metadata provider).
You can specify which property you are refering to in a strongly typed helper, look for overload with 3 parameters.
Nothing wrong with your method. Strongly typed views are there to help you develop better, so no typpo can get in your way.
I would suggest to keep it simple by just using one object for GET and POST. Code maintainability is far more important/valuable here than saving a few bytes for an update action.
Arnis makes good arguments regarding SRP and other design patterns but petterns are supposed to be adapted. If i were you i'd use the help the mvc framework has created for you: use the typed helpers; use typed model/viewmodel objects for GET/POST and if you need more complex binding create a custom binder.
Keep your code light and ur app will stay awesome.
I use a model for input (displayed by the form) and a separate model for output (posted by the form). Validation is placed on the output model. The specific reason why I do this is for drop down lists. You want a list of possible values to present to the user and these are in the input model. In the output or post from the form I don't want the list of possible value, I want to know what values the user selected, if any.
I use separate view models for input [GET] and output [POST] as well, unless the two models are identical. IMHO this approach is cleaner, easier to maintain, and more clearly expresses which data will be updated by a given controller action.
There's a cost in terms of LOC, but the extra code is usually not logic. In most cases, I don't feel that duplicating some automatic properties on two objects violates the DRY principle, and I think the cost is justified to follow SRP.
The other cost, as you've noted, is that the built-in strongly typed helpers don't work so well. Have you thought about writing your own helpers that support your pattern? For instance, you might overload one of the existing helpers so that you can specify both the source (e.g. the property of the input model) and the destination (e.g. the name of the form field that is posted to the output model).
Just looking at your specific situation, the following points occur to me.
1) The two models are very similar indeed 2) If you add "MiddleName", you have to add it in two places 3) When you say "I only want to pass back a slim object" - the actual POST will contain the same amount of data, whether you bind to the original model or a new one (it will contain a key, value pair for each user-input within the form) 4) You preclude the option of displaying the data on your "saved ok" or "something isn't valid" page as it isn't part of the model
For these reasons, I would recommend using the same model for the GET and POST of the action.
Most of the time the auto-binding stuff doesn't fit what I need so I just resort to posting to a formCollection
parameter and go manual. If you can use any part of the model binding magic then all the better for you.
Binding less doesn't mean less data is posted back to the server. All of the input elements in the form will be transmitted, you just wont see them as discrete, strongly typed, "automagic" parameters. If you really want to slim down the post data you have to restrict what input elements are inside the particular form you post. MVC is still HTTP after all...
精彩评论