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.
My approach is to add conditional checking annotation attribute, which is learned from foolproof.
Make
SaveMode
part of the view model.Mark the properties nullable so that the values of which are optional when
SaveMode
is notFinalize
.But add a custom annotation attribute
[FinalizeRequired]
:Here is the code for the Attribute:
For primitive data types, check
value!=null
:For
IEnumerable
collections,This approach best achieves the separation of concerns by removing validation logic out of controller. Data Annotation attributes should handle that kind of work, which controller just need a check of
!ModelState.IsValid
. This is especially useful in my application, because I would not be able to refactor into a base controller ifModelState
check is different in each controller.