i\'ve got a sign up wizard for new user registration. When I try to goto the 2nd page, I get validation errors because my User
object hasn\'t been fully populated,
This is discussed in Steve Sanderson's asp.net mvc 2 book, page 486.
Create a a custom attribute, ValidateIncomingValuesOnlyAttribute, that inherits from ActionFilterAttribute, and apply it to your controller class.
Override the OnActionExecuting method:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
var incomingValues = filterContext.Controller.ValueProvider;
var keys = modelState.Keys.Where(x => !incomingValues.ContainsPrefix(x));
foreach(var key in keys)
{
modelState[key].Errors.Clear();
}
}
That way you validate the data the pertains to each step in the wizard only. You then need a confirmation page with no data input to send off the validated data to the server.
But most of all, read Steve Sanderson's book, it gives a working solution to this and your other problem.
If instead of the above you decide to map to a viewmodel, be careful because you will either have to:
a. Not decorate the viewmodel properties with validation dataannotation attributes, in which case you only validate once the user has filled in the entire wizard and try to submit to the database. This would be very naff from the user's perspective...
b. Else, you still have to use the technique described by S Sanderson, ie, clear any validation errors that don't pertain to the fields on the current step.
I don't see the accepted answer as answering the question as it was asked.
I was just messing with validation forms and ModelState
and found out a very easy solution to your problem without writing any new method, overrides etc.
ModelState.Where(m => m.Key == "Avatar").FirstOrDefault().Value.Errors.Clear();
// At this point ModeState will have an error for that Key,
// by applying Clear it remove the error so modelstate becomes valid again
if (!ModelState.IsValid) {
return View("User", model);
} else {
try {
// do something
} catch {
TempData["errorMessage"] = "something went wrong";
}
}
You can use the Bind Attribute for this: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/
A better option would be to use ViewModels.
http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx