Reputation: 14879
I have a method that validates a number, I don't have a regular expression for this as it is kind of complicated to create.
public bool IsRegistrationNumberValid(int number)
{
...
}
On my form, I have a textbox and I want to add validation for this column. How can I create a custom annotation or hook into the ModelState object to add an error message?
My POST controller action is like:
[HttpPost]
public ActionResult Create(UserRegistrationViewData model)
{
if (ModelState.IsValid)
{
...
}
}
I'm not sure what options I have, can I just create a custom attribute to add to my model?
And/Or should i just hook into the Model state and add the error message before I check for ModelState.IsValid
?
Upvotes: 3
Views: 3396
Reputation: 13177
There are a few approaches to this and the best one for you will depend on the following:
IsRegistrationNumberValid
method is located and whether the the logic be moved?The way I see it you have the following options available:
IValidatableObject
interface.ValidationAttribute
.Option 1: Validate in your controller:
First of all you could simply validate the value in your controllers action method and update the ModelState
like so:
[HttpPost]
public ActionResult Create(UserRegistrationViewData model)
{
if (ModelState.IsValid)
{
if (!someObject.IsRegistrationNumberValid(model.value))
{
ModelState.AddModelError("PropertyName", "There is an error..");
Return View()
}
else
{
// Carry out successful action here...
}
}
}
Option 2: use the IValidatableObject
interface.
A second, much cleaner way is to implement the IValidatableObject
interface on your viewModel so that you can move the logic out of the controller:
public class ViewModel : IValidatableObject
{
public int Value { get; set; }
IEnumerable<ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
{
if (!staticClass.IsRegistrationNumberValid(this.Value))
{
yield return new ValidationResult("An error occured");
}
}
Option 3: Create a custom validation attribute.
As mentioned you could create a custom validation attribute by deriving from ValidationAttribute
as shown in this article.
The choice between the IvalidatableObject
interface and a custom validation attribute is usually down to preference, however, one case where the IValidatableObject
interface wins is when your validation depends on multiple properties (E.G. checking if one date is after another).
Option 4: Validate in your service layer.
Finally, if your validation is dependant on other information from a database you might want to take a look at this tutorial on validating with a service layer. The article is not perfect (the service and controller are a bit too tightly coupled) but is a good start and with a few modifications you can pass database validation errors (such as primary key violations) into your user interface in a very transparent and user-friendly way.
You will probably end up using a mixture of options 2, 3, and 4. You don't really want to be using the first option if possible as it makes your controller methods more complicated and makes it more difficult to reuse validation logic elsewhere.
My advice would be the following:
IValidatableObject
interface and the ValidationAttribute
classes.Upvotes: 10