We came up with another solution that I thought I would share.
This is based on a view model that contains information about what actions it can do, but we believe that the controller should specify these (i.e., control which actions use different links), because we have cases when view models reuse used in actions. EG, the case when you can edit a template or an instance of something while editing - the user interface is the same, the only difference is the actions that you send to / cancel.
We distracted the part of the presentation model, which contains the properties associated with the data, and the presentation model, which contains the other things we need to render the view. We call the object only for the DTO object - this is not a true dto, because it contains validation attributes.
We believe that we will be able to reuse these DTOs in the future for ajax or even XML requests - it can continue to validate DRY.
In any case - here is a sample code, we are happy with it (for now) and hope that it will help others.
[HttpGet] [ValidateInput(false)] public virtual ActionResult ManageUser(ManageUserDTO dto, bool PopulateFromObject = true) { User user = this._UserLogic.GetUser(dto.UserID); if (PopulateFromObject) Mapper.Map<User, ManageUserDTO>(user, dto); ManageUserViewModel vm = new ManageUserViewModel() { DTO = dto, PageTitle = Captions.GetCaption("pageTitle_EditUser"), OnSubmit = GetSubmitEventData(this.ControllerName, "SaveUser"), OnCancel = GetCancelEventData(this.ControllerName, "ListUsers"), }; return View("ManageUser", vm); } [HttpPost] public virtual ActionResult SaveUser(ManageUserViewModel vm) { User user = this._UserLogic.GetUser(vm.DTO.UserID); if (!ModelState.IsValid) { return ManageUser(vm.DTO, false); } Mapper.Map<ManageUserDTO, User>(vm.DTO, user); this._UserLogic.SaveUser(user); TempData.AddSuccess(Captions.GetCaption("message_UserSavedSuccessfuly")); return RedirectToAction("ManageUser", new { UserID = user.ID }); }
The binder model sets any URI variables in dto in the get action. My logic level will return a new User object if getUserByID (null) is called.