Asp.net MVC source code analysis-Model Validation (Server side) Implementation (2)

Source: Internet
Author: User

We have introduced the usage of Model Validation and the method implementation of ValidateModel. This article describes the implementation of the DataAnnotationsModelValidatorProvider class in detail.

Iii. DataAnnotationsModelValidatorProvider class details
1. AttributeFactories object
First, we can see in this class that the AttributeFactories object (Dictionary) was created during initialization. This set contains some built-in verification rules.
1 internal static Dictionary <Type, DataAnnotationsModelValidationFactory> AttributeFactories = new Dictionary <Type, DataAnnotationsModelValidationFactory> (){
2 {
3 typeof (RangeAttribute ),
4 (metadata, context, attribute) => new RangeAttributeAdapter (metadata, context, (RangeAttribute) attribute)
5 },
6 {
7 typeof (RegularExpressionAttribute ),
8 (metadata, context, attribute) => new RegularExpressionAttributeAdapter (metadata, context, (RegularExpressionAttribute) attribute)
9 },
10 {
11 typeof (requiredattriof ),
12 (metadata, context, attribute) => new RequiredAttributeAdapter (metadata, context, (RequiredAttribute) attribute)
13 },
14 {
15 typeof (StringLengthAttribute ),
16 (metadata, context, attribute) => new StringLengthAttributeAdapter (metadata, context, (StringLengthAttribute) attribute)
17 },
18}
19}
Copy code
2. Application of the ValidationAttribte Adapter design mode
Note that MVC uses * AttributeAdapter to adapt the GetValidationResult method of ValidationAttribte to ModelValidator. Validate method (the Adapter mode is used here). For details, see RangeAttributeAdapter/modules/RequiredAttributeAdapter/feature.
Please refer to the source code of DataAnnotationsModelValidator. Validate method. The 7th line of code is adapted here.
1 public override IEnumerable <ModelValidationResult> Validate (object container ){
2 // Per the wcf ria Services team, instance can never be null (if you have
3 // no parent, you pass yourself for the "instance" parameter ).
4 ValidationContext context = new ValidationContext (container ?? Metadata. Model, null, null );
5 context. DisplayName = Metadata. GetDisplayName ();
6
7 ValidationResult result = Attribute. GetValidationResult (Metadata. Model, context );
8 if (result! = ValidationResult. Success ){
9 yield return new ModelValidationResult {
10 Message = result. ErrorMessage
11 };
12}
13}
Copy code
3. Get the ModelValidator object set
Next, let's analyze the implementation of the DataAnnotationsModelValidatorProvider. GetValidators method.
1 protected override IEnumerable <ModelValidator> GetValidators (ModelMetadata metadata, ControllerContext context, IEnumerable <Attribute> attributes ){
2 _ adaptersLock. EnterReadLock ();
3
4 try {
5 List <ModelValidator> results = new List <ModelValidator> ();
6
7 // Add an implied [Required] attribute for any non-nullable value type,
8 // unless they 've configured us not to do that.
9 if (AddImplicitRequiredAttributeForValueTypes &&
10 metadata. IsRequired &&
11! Attributes. Any (a => a is RequiredAttribute )){
12 attributes = attributes. Concat (new [] {new RequiredAttribute ()});
13}
14
15 // Produce a validator for each validation attribute we find
16 foreach (ValidationAttribute attribute in attributes. OfType <ValidationAttribute> ()){
17 DataAnnotationsModelValidationFactory factory;
18 if (! AttributeFactories. TryGetValue (attribute. GetType (), out factory )){
19 factory = defaultattriattributefactory;
20}
21 results. Add (factory (metadata, context, attribute ));
22}
23
24 // Produce a validator if the type supports IValidatableObject
25 if (typeof (IValidatableObject). IsAssignableFrom (metadata. ModelType )){
26 DataAnnotationsValidatableObjectAdapterFactory factory;
27 if (! ValidatableFactories. TryGetValue (metadata. ModelType, out factory )){
28 factory = defavalivalidatablefactory;
29}
30 results. Add (factory (metadata, context ));
31}
32
33 return results;
34}
35 finally {
36_adapterslock. ExitReadLock ();
37}
38}
Copy code
From line 16 to 22, MVC finds the DataAnnotationsModelValidationFactory that matches AttributeFactories from the Attributes attribute, and calls the ModelValidator object to return, but if no matching object is found from AttributeFactories, use DefaultAttributeFactory to create a ModelValidator object.
The internal implementation of DefaultAttributeFactory is to create a DataAnnotationsModelValidator object and pass in ValidationAttribute during construction. In fact, this class is also the base class of * AttributeAdapter class such as RangeAttributeAdapter, and their initialization logic is the same.
1 internal static DataAnnotationsModelValidationFactory defaultbutefactory =
2 (metadata, context, attribute) => new DataAnnotationsModelValidator (metadata, context, attribute );
Copy code
4. IValidatableObject Interface
Finally, let's take a look at the line 25-30 of the DataAnnotationsModelValidatorProvider. GetValidators method.
In this method, we also found that MVC uses the ValidatableObjectAdapter adapter to connect to the ModelValidator. Validate method and the IValidatableObject. Validate interface.
BTW: The IValidatableObject interface can be used to verify the logical relationship between attributes of the model.
See another article: http://www.cnblogs.com/bjs007/archive/2011/01/27/1946419.html.
Summary:
• Model Validatoin can be verified by adding * ValidationAttribute to the Modol attribute and implementing the IValidatableObject interface.
• By analyzing DataAnnotationsModelValidatorProvider. GetValidators:
If the attribute in the Model is a complex object, it is not verified even if * ValidationAttribute is marked in the sub-object.
For example, the following code: although the attribute in the LogOnModel. ChangePassword object is marked with [Required], it is still not verified.
1 public class ChangePasswordModel
2 {
3 [Required]
4 [DataType (DataType. Password)]
5 [Display (Name = "Current password")]
6 public string OldPassword {get; set ;}
7
8 [Required]
9 [ValidatePasswordLength]
10 [DataType (DataType. Password)]
11 [Display (Name = "New password")]
12 public string NewPassword {get; set ;}
13
14 [DataType (DataType. Password)]
15 [Display (Name = "Confirm new password")]
16 [Compare ("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
17 public string ConfirmPassword {get; set ;}
18}
19
20 public class LogOnModel: IValidatableObject
21 {
22 [Required]
23 [Display (Name = "User name")]
24 public string UserName {get; set ;}
25 [Required]
26 [Display (Name = "User age")]
27 public string Age {get; set ;}
28 [Required]
29 [DataType (DataType. Password)]
30 [Display (Name = "Password")]
31 public string Password {get; set ;}
32 [Display (Name = "Remember me? ")]
33 public bool RememberMe {get; set ;}
34 [Display (Name = "ChangePassword")]
35 // [Required]
36 public ChangePasswordModel ChangePassword {get; set ;}
37
38 public IEnumerable <ValidationResult> Validate (ValidationContext validationContext)
39 {
40 return Enumerable. Empty <ValidationResult> ();
41}
42}
Copy code
Question
Another confusing thing is that if you set the LogOnModel. if the ChangePassword attribute is marked with [Required] And this object is not passed in from the foreground, verification on all LogOnModel attributes will fail. This is not a bug in Asp.net MVC, if someone encounters this problem, please let me know.

From the rain of November

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.