Reputation: 16264
I would like to use the built-in validation features as far as possible. I would also like to use the same model for CRUD methods.
However, as a drop down list cannot be done using the standard pattern, I have to validate it manually. In the post back method, I would like to just validate the drop down list and add this result to ModelState so that I don't have to validate all the other parameters which are done with Data Annotation. Is it possible to achieve this?
I may be mistaken about the drop down list, but from what I read, the Html object name for a drop down list cannot be the same as the property in the Model in order for the selected value to be set correctly. Is it still possible to use Data Annotation with this workaround?
Thanks.
Upvotes: 32
Views: 44336
Reputation: 1141
Might be more recent methods, since this is an old post, but this might help future readers.
One can set a field to valid with this two methods:
ModelState.ClearValidationState("Password");
ModelState.MarkFieldValid("Password");
Need to use both because the second one without the first one it gives an error stating that the state is already marked.
To set a field to invalid, just use ModelState.AddModelError() method as already referred.
Upvotes: 1
Reputation: 11515
yes, you can achieve this (also you will use the same model for CRUD methods) :
Example MODEL
public class User
{
public virtual int Id{ get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
[Required(ErrorMessage = "Id Required.")]
public virtual int Id { get; set; }
[Required(ErrorMessage = "Name Required.")]
public virtual string Name { get; set; }
}
Example VIEW with validation on the dropdownlist
@Html.DropDownListFor(m => m.Role.Id, (SelectList)ViewBag.gRoles, "-- Select --")
@Html.ValidationMessageFor(m => m.Role.Id)
CONTROLLER: clearing the required (but not needed here) fields
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Creedit(User x)
{
x.Role = db.RoseSet.Find(x.Role.Id);
if (x.Role != null)
{
ModelState["Role.Name"].Errors.Clear();
}
if (ModelState.IsValid)
{
// proceed
}
else
{
// return validation error
}
}
Upvotes: 4
Reputation: 6524
Another option is to inherit IValidatableObject
in your model. Implement its Validate
method and you can leave all other validation in place and write whatever code you want in this method. Note: you return an empty IEnumerable<ValidationResult>
to indicate there were no errors.
public class Class1 : IValidatableObject
{
public int val1 { get; set; }
public int val2 { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var errors = new List<ValidationResult>();
if (val1 < 0)
{
errors.Add(new ValidationResult("val1 can't be negative", new List<string> { "val2" }));
}
if (val2 < 0)
{
errors.Add(new ValidationResult("val2 can't be negative", new List<string> { "val2" }));
}
return errors;
}
}
EDIT: After re-reading the question I don't think this applicable to this case, but I'm leaving the answer here in case it helps someone else.
Upvotes: 18
Reputation: 196217
You can use the addModelError
ModelState.AddModelError(key,message)
when you use that, it will invalidate the ModelState so isValid
will return false.
Update
after seeing the comment to @Pieter's answer
If you want to exclude an element from affecting the isValid()
result, you can use the ModelState.Remove(field)
method before calling isValid()
.
Upvotes: 80
Reputation: 4886
You cannot manually set the ModelState.IsValid property but you can add messages to the ModelState that will ensure that the IsValid is false.
ModelState.AddModelError();
Upvotes: 5