Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to selectively validate some data annotation attribute?

There are some properties in my view model that are optional when saving, but required when submitting. In a word, we allow partial saving, but the whole form is submitted, we do want to make sure all required fields have values.

The only approaches I can think of at this moment are:

Manipulate the ModelState errors collection.

The view model has all [Required] attributes in place. If the request is partial save, the ModelState.IsValid becomes false when entering the controller action. Then I run through all ModelState (which is an ICollection<KeyValuePair<string, ModelState>>) errors and remove all errors raised by [Required] properties.

But if the request is to submit the whole form, I will not interfere with the ModelState and the [Required] attributes take effect.

Use different view models for partial save and submit

This one is even more ugly. One view model will contain all the [Required] attributes, used by an action method for submitting. But for partial save, I post the form data to a different action which use a same view model without all the [Required] attributes.

Obviously, I would end up with a lot of duplicate code / view models.

The ideal solution

I have been thinking if I can create a custom data annotation attribute [SubmitRequired] for those required properties. And somehow make the validation ignores it when partial saving but not when submitting.

Still couldn't have a clear clue. Anyone can help? Thanks.

like image 946
Blaise Avatar asked Oct 19 '22 09:10

Blaise


1 Answers

This is one approach I use in projects.

Create a ValidationService<T> containing the business logic that will check that your model is in a valid state to be submitted with a IsValidForSubmission method.

Add an IsSubmitting property to the view model which you check before calling the IsValidForSubmission method.

Only use the built in validation attributes for checking for invalid data i.e. field lengths etc.

Create some custom attributes within a different namespace that would validate in certain scenarios i.e. [RequiredIfSubmitting] and then use reflection within your service to iterate over the attributes on each property and call their IsValid method manually (skipping any that are not within your namespace).

This will populate and return a Dictionary<string, string> which can be used to populate ModelState back to the UI:

var validationErrors = _validationService.IsValidForSubmission(model);

if (validationErrors.Count > 0)
{
    foreach (var error in validationErrors)
    {
        ModelState.AddModelError(error.Key, error.Value);
    }
}
like image 181
hutchonoid Avatar answered Nov 01 '22 15:11

hutchonoid