File: ModelValidationNode.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (174 lines) | stat: -rw-r--r-- 7,058 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
namespace System.Web.ModelBinding {
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public sealed class ModelValidationNode {

        public ModelValidationNode(ModelMetadata modelMetadata, string modelStateKey)
            : this(modelMetadata, modelStateKey, null) {
        }

        public ModelValidationNode(ModelMetadata modelMetadata, string modelStateKey, IEnumerable<ModelValidationNode> childNodes) {
            if (modelMetadata == null) {
                throw new ArgumentNullException("modelMetadata");
            }
            if (modelStateKey == null) {
                throw new ArgumentNullException("modelStateKey");
            }

            ModelMetadata = modelMetadata;
            ModelStateKey = modelStateKey;
            ChildNodes = (childNodes != null) ? childNodes.ToList() : new List<ModelValidationNode>();
        }

        public ICollection<ModelValidationNode> ChildNodes {
            get;
            private set;
        }

        public ModelMetadata ModelMetadata {
            get;
            private set;
        }

        public string ModelStateKey {
            get;
            private set;
        }

        public bool ValidateAllProperties {
            get;
            set;
        }

        public bool SuppressValidation {
            get;
            set;
        }

        public event EventHandler<ModelValidatedEventArgs> Validated;

        public event EventHandler<ModelValidatingEventArgs> Validating;

        public void CombineWith(ModelValidationNode otherNode) {
            if (otherNode != null && !otherNode.SuppressValidation) {
                Validated += otherNode.Validated;
                Validating += otherNode.Validating;
                foreach (ModelValidationNode childNode in otherNode.ChildNodes) {
                    ChildNodes.Add(childNode);
                }
            }
        }

        private void OnValidated(ModelValidatedEventArgs e) {
            EventHandler<ModelValidatedEventArgs> handler = Validated;
            if (handler != null) {
                handler(this, e);
            }
        }

        private void OnValidating(ModelValidatingEventArgs e) {
            EventHandler<ModelValidatingEventArgs> handler = Validating;
            if (handler != null) {
                handler(this, e);
            }
        }

        private object TryConvertContainerToMetadataType(ModelValidationNode parentNode) {
            if (parentNode != null) {
                object containerInstance = parentNode.ModelMetadata.Model;
                if (containerInstance != null) {
                    Type expectedContainerType = ModelMetadata.ContainerType;
                    if (expectedContainerType != null) {
                        if (expectedContainerType.IsInstanceOfType(containerInstance)) {
                            return containerInstance;
                        }
                    }
                }
            }

            return null;
        }

        public void Validate(ModelBindingExecutionContext modelBindingExecutionContext) {
            Validate(modelBindingExecutionContext, null /* parentNode */);
        }

        public void Validate(ModelBindingExecutionContext modelBindingExecutionContext, ModelValidationNode parentNode) {
            if (modelBindingExecutionContext == null) {
                throw new ArgumentNullException("modelBindingExecutionContext");
            }

            if (SuppressValidation) {
                // no-op
                return;
            }

            // pre-validation steps
            ModelValidatingEventArgs eValidating = new ModelValidatingEventArgs(modelBindingExecutionContext, parentNode);
            OnValidating(eValidating);
            if (eValidating.Cancel) {
                return;
            }

            ValidateChildren(modelBindingExecutionContext);
            ValidateThis(modelBindingExecutionContext, parentNode);

            // post-validation steps
            ModelValidatedEventArgs eValidated = new ModelValidatedEventArgs(modelBindingExecutionContext, parentNode);
            OnValidated(eValidated);
        }

        private void ValidateChildren(ModelBindingExecutionContext modelBindingExecutionContext) {
            foreach (ModelValidationNode child in ChildNodes) {
                child.Validate(modelBindingExecutionContext, this);
            }

            if (ValidateAllProperties) {
                ValidateProperties(modelBindingExecutionContext);
            }
        }

        private void ValidateProperties(ModelBindingExecutionContext modelBindingExecutionContext) {
            // Based off CompositeModelValidator.
            ModelStateDictionary modelState = modelBindingExecutionContext.ModelState;

            // DevDiv Bugs #227802 - Caching problem in ModelMetadata requires us to manually regenerate
            // the ModelMetadata.
            object model = ModelMetadata.Model;
            ModelMetadata updatedMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, ModelMetadata.ModelType);

            foreach (ModelMetadata propertyMetadata in updatedMetadata.Properties) {
                // Only want to add errors to ModelState if something doesn't already exist for the property node,
                // else we could end up with duplicate or irrelevant error messages.
                string propertyKeyRoot = ModelBinderUtil.CreatePropertyModelName(ModelStateKey, propertyMetadata.PropertyName);

                if (modelState.IsValidField(propertyKeyRoot)) {
                    foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(modelBindingExecutionContext)) {
                        foreach (ModelValidationResult propertyResult in propertyValidator.Validate(model)) {
                            string thisErrorKey = ModelBinderUtil.CreatePropertyModelName(propertyKeyRoot, propertyResult.MemberName);
                            modelState.AddModelError(thisErrorKey, propertyResult.Message);
                        }
                    }
                }
            }
        }

        private void ValidateThis(ModelBindingExecutionContext modelBindingExecutionContext, ModelValidationNode parentNode) {
            ModelStateDictionary modelState = modelBindingExecutionContext.ModelState;
            if (!modelState.IsValidField(ModelStateKey)) {
                return; // short-circuit
            }

            object container = TryConvertContainerToMetadataType(parentNode);
            foreach (ModelValidator validator in ModelMetadata.GetValidators(modelBindingExecutionContext)) {
                foreach (ModelValidationResult validationResult in validator.Validate(container)) {
                    string trueModelStateKey = ModelBinderUtil.CreatePropertyModelName(ModelStateKey, validationResult.MemberName);
                    modelState.AddModelError(trueModelStateKey, validationResult.Message);
                }
            }
        }

    }
}