I’ve been struggling with this annoying problem. I have a Model, Editor and controller:
public class TeamDetails{
public int SeasonId{get;set;}
public TeamDetails()
{
//need SeasonId to be populated already from form here, but it won't yet.
}
public TeamDetails(int seasonId)
: this()
{
//load dropdownlist using seasonId from repository
}
}
//Controller
//get method gets seasonId from querystring.
public ViewResult Create(int seasonId)
{
// calls the parameterized constructor for TeamDetails
// which uses seasonId to populate a dropdownlist from db repo.
var teamDetails = new TeamDetails(seasonId);
}
[HttpPost]
public PartialViewResult Create(TeamDetails model)
{
// no such luxury here to call the parameterized
// Constructor for model. additional logic.
}
//editor
@using (Ajax.BeginForm("Create", "Team", options))
{
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.SeasonId)
//additional fields
}
I need to have the SeasonId from the hidden field already be populated by the time TeamDetails constructor is hit as I need that in the constructor. However, that obviously can’t happen because the constructor is called before the MVC has a chance to assign SeasonId to the object. Any way I can get around this?
Thanks
Riz
I would advise against embedding logic like this in your view models (such as determining team data from a SeasonId). Treat your ViewModels as plain flat objects with properties only. Apply what ever input validation attributes you want to on your view models, and then in your action that handles the postback check your modelstate for validation problems. Business rules validation is probably something you won’t be able to do in the controller as you may need information from other sources like the database etc. Those should be in your business layer, I raise these problems as a DomainException, and then in my controller capture them in a try catch and add any DomainExceptions to the ModelState as a ModelError. Then do your normal test if ModelState.IsValid. Once your model is valid you can create an internal instance of your TeamDetails class if you must and deal with it’s inner working under your full control. Though I would recommend keeping the actual business logic of what you do with the view data in a business layer and not in the controller. Think of the controller as a means of passing information from the view models to your business/service layer and that’s it.
Here’s some pseudo code to show what I mean, I haven’t checked if this is syntactically correct but you get the idea.
.
EDIT:
For dealing with dropdowns and other things that you need to have pre-populated I would suggest also using a view model. The easiest way is to just inherit from your model expected for the postback and add on any properties that you need in the view but don’t expect to be posted back to the server upon submit.
For simplicity, I am using Linq to get a collection of SelectListItem from the collection
GetSeasons()is likely to return. There are other considerations to look at as well such as having the first item be something like “— Please pick one—” or the likeThe view would have something like this…