1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.Components
.Validator
18 using System
.Collections
;
19 using System
.Collections
.Generic
;
20 using System
.Reflection
;
23 /// Coordinates the gathering and execution of validators.
24 /// <seealso cref="IValidatorRegistry"/>
27 /// This class is not thread safe and should not be shared. It should only be
28 /// used in small scopes and discarded.
31 /// ValidatorRunner runner = new ValidatorRunner(new CachedValidationRegistry());
33 /// if (!runner.IsValid(customer))
35 /// // do something as the Customer instance is not valid
38 public class ValidatorRunner
40 private readonly static IDictionary
<Type
, Type
> type2Validator
;
41 private readonly IDictionary extendedProperties
= new Hashtable();
42 private readonly IDictionary
<object, ErrorSummary
> errorPerInstance
;
43 private readonly bool inferValidators
;
44 private readonly IValidatorRegistry registry
;
46 static ValidatorRunner()
48 type2Validator
= new Dictionary
<Type
, Type
>();
49 type2Validator
[typeof(Int16
)] = typeof(IntegerValidator
);
50 type2Validator
[typeof(Nullable
<Int16
>)] = typeof(NullableIntegerValidator
);
51 type2Validator
[typeof(Int32
)] = typeof(IntegerValidator
);
52 type2Validator
[typeof(Nullable
<Int32
>)] = typeof(NullableIntegerValidator
);
53 type2Validator
[typeof(Int64
)] = typeof(IntegerValidator
);
54 type2Validator
[typeof(Nullable
<Int64
>)] = typeof(NullableIntegerValidator
);
55 type2Validator
[typeof(Decimal
)] = typeof(DecimalValidator
);
56 type2Validator
[typeof(Nullable
<Decimal
>)] = typeof(NullableDecimalValidator
);
57 type2Validator
[typeof(Single
)] = typeof(SingleValidator
);
58 type2Validator
[typeof(Nullable
<Single
>)] = typeof(NullableSingleValidator
);
59 type2Validator
[typeof(Double
)] = typeof(DoubleValidator
);
60 type2Validator
[typeof(Nullable
<Double
>)] = typeof(NullableDoubleValidator
);
61 type2Validator
[typeof(DateTime
)] = typeof(DateTimeValidator
);
62 type2Validator
[typeof(Nullable
<DateTime
>)] = typeof(NullableDateTimeValidator
);
66 /// Initializes a new instance of the <see cref="ValidatorRunner"/> class.
68 /// <param name="registry">The registry.</param>
69 public ValidatorRunner(IValidatorRegistry registry
) : this(false, registry
)
74 /// Initializes a new instance of the <see cref="ValidatorRunner"/> class.
76 /// <param name="inferValidators">If true, the runner will try to infer the validators based on data types</param>
77 /// <param name="registry">The registry.</param>
78 public ValidatorRunner(bool inferValidators
, IValidatorRegistry registry
)
80 if (registry
== null) throw new ArgumentNullException("registry");
82 this.inferValidators
= inferValidators
;
84 errorPerInstance
= new Dictionary
<object, ErrorSummary
>();
86 this.registry
= registry
;
90 /// Determines whether the specified instance is valid.
92 /// All validators are run.
95 /// <param name="objectInstance">The object instance to be validated (cannot be null).</param>
97 /// <see langword="true"/> if the specified obj is valid; otherwise, <see langword="false"/>.
99 public bool IsValid(object objectInstance
)
101 return IsValid(objectInstance
, RunWhen
.Everytime
);
105 /// Determines whether the specified instance is valid.
107 /// All validators are run for the specified <see cref="RunWhen"/> phase.
110 /// <param name="objectInstance">The object instance to be validated (cannot be null).</param>
111 /// <param name="runWhen">Restrict the set returned to the phase specified</param>
113 /// <see langword="true"/> if the specified instance is valid; otherwise, <see langword="false"/>.
115 public bool IsValid(object objectInstance
, RunWhen runWhen
)
117 if (objectInstance
== null) throw new ArgumentNullException("objectInstance");
121 ErrorSummary summary
= new ErrorSummary();
123 foreach(IValidator validator
in GetValidators(objectInstance
, runWhen
))
125 if (!validator
.IsValid(objectInstance
))
127 string name
= validator
.FriendlyName
?? validator
.Name
;
129 summary
.RegisterErrorMessage(name
, validator
.ErrorMessage
);
135 errorPerInstance
[objectInstance
] = summary
;
141 /// Gets the registered validators.
143 /// <param name="parentType">Type of the parent.</param>
144 /// <param name="property">The property.</param>
145 /// <returns></returns>
146 public IValidator
[] GetValidators(Type parentType
, PropertyInfo property
)
148 return GetValidators(parentType
, property
, RunWhen
.Everytime
);
152 /// Gets the registered validators.
154 /// <param name="parentType">Type of the parent.</param>
155 /// <param name="property">The property.</param>
156 /// <param name="runWhenPhase">The run when phase.</param>
157 /// <returns></returns>
158 public IValidator
[] GetValidators(Type parentType
, PropertyInfo property
, RunWhen runWhenPhase
)
160 if (parentType
== null) throw new ArgumentNullException("parentType");
161 if (property
== null) throw new ArgumentNullException("property");
163 IValidator
[] validators
= registry
.GetValidators(this, parentType
, property
, runWhenPhase
);
165 if (inferValidators
&& validators
.Length
== 0)
167 Type defaultValidatorForType
= (Type
) type2Validator
[property
.PropertyType
];
169 if (defaultValidatorForType
!= null)
171 validators
= new IValidator
[] {(IValidator) Activator.CreateInstance(defaultValidatorForType)}
;
173 validators
[0].Initialize(registry
, property
);
177 Array
.Sort(validators
, ValidatorComparer
.Instance
);
183 /// Gets the error list per instance.
185 /// <param name="instance">The instance.</param>
186 /// <returns></returns>
187 public bool HasErrors(object instance
)
189 ErrorSummary summary
= GetErrorSummary(instance
);
191 if (summary
== null) return false;
193 return summary
.ErrorsCount
!= 0;
197 /// Gets the error list per instance.
199 /// <param name="instance">The instance.</param>
200 /// <returns></returns>
201 public ErrorSummary
GetErrorSummary(object instance
)
203 return errorPerInstance
.ContainsKey(instance
) ? errorPerInstance
[instance
] : null;
207 /// Gets the extended properties, which allows <see cref="IValidator"/>
208 /// implementation to store additional information to track state.
210 /// <value>The extended properties.</value>
211 public IDictionary ExtendedProperties
213 get { return extendedProperties; }
216 private IValidator
[] GetValidators(object objectInstance
, RunWhen runWhen
)
218 if (objectInstance
== null) throw new ArgumentNullException("objectInstance");
220 IValidator
[] validators
= registry
.GetValidators(this, objectInstance
.GetType(), runWhen
);
222 Array
.Sort(validators
, ValidatorComparer
.Instance
);
227 private class ValidatorComparer
: IComparer
229 private static readonly ValidatorComparer instance
= new ValidatorComparer();
231 public int Compare(object x
, object y
)
233 IValidator left
= (IValidator
) x
;
234 IValidator right
= (IValidator
) y
;
236 return left
.ExecutionOrder
- right
.ExecutionOrder
;
239 public static ValidatorComparer Instance
241 get { return instance; }