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
;
21 /// Specifies the data type the <see cref="RangeValidator"/>
24 public enum RangeValidationType
27 /// <see cref="RangeValidator"/> is dealing with a range of integers
31 /// <see cref="RangeValidator"/> is dealing with a range of decimals
35 /// <see cref="RangeValidator"/> is dealing with a range of dates
39 /// <see cref="RangeValidator"/> is dealing with a range of strings
45 /// Ensures that a property's string representation
46 /// is within the desired value limitations.
49 public class RangeValidator
: AbstractValidator
51 private object min
, max
;
52 private RangeValidationType type
;
55 /// Initializes an integer-based range validator.
57 /// <param name="min">The minimum value, or <c>int.MinValue</c> if this should not be tested.</param>
58 /// <param name="max">The maximum value, or <c>int.MaxValue</c> if this should not be tested.</param>
59 public RangeValidator(int min
, int max
)
61 AssertValid(max
, min
);
63 type
= RangeValidationType
.Integer
;
69 /// Initializes an decimal-based range validator.
71 /// <param name="min">The minimum value, or <c>decimal.MinValue</c> if this should not be tested.</param>
72 /// <param name="max">The maximum value, or <c>decimal.MaxValue</c> if this should not be tested.</param>
73 public RangeValidator(decimal min
, decimal max
)
75 AssertValid(max
, min
);
77 type
= RangeValidationType
.Decimal
;
83 /// Initializes a DateTime-based range validator.
85 /// <param name="min">The minimum value, or <c>DateTime.MinValue</c> if this should not be tested.</param>
86 /// <param name="max">The maximum value, or <c>DateTime.MaxValue</c> if this should not be tested.</param>
87 public RangeValidator(DateTime min
, DateTime max
)
89 AssertValid(max
, min
);
91 type
= RangeValidationType
.DateTime
;
97 /// Initializes a string-based range validator.
99 /// <param name="min">The minimum value, or <c>String.Empty</c> if this should not be tested.</param>
100 /// <param name="max">The maximum value, or <c>String.Empty</c> if this should not be tested.</param>
101 public RangeValidator(string min
, string max
)
103 AssertValid(max
, min
);
105 type
= RangeValidationType
.String
;
111 /// Initializes a range validator of the given type with the given minimum and maximum values.
113 /// <param name="type">The type of range validator.</param>
114 /// <param name="min">The minimum value, or <c>null</c> if this should not be tested.</param>
115 /// <param name="max">The maximum value, or <c>null</c> if this should not be tested.</param>
116 public RangeValidator(RangeValidationType type
, object min
, object max
)
119 this.min
= GetMinValue(min
);
120 this.max
= GetMaxValue(max
);
124 /// Gets or sets the range validation type for this validator. If the type is changed,
125 /// the minimum and maximum values are reset to null-equivalent values (i.e. appropriate
126 /// minimum and maximum values for the data type).
128 public RangeValidationType Type
136 min
= GetMinValue(null);
137 max
= GetMaxValue(null);
144 /// Internal method that checks a given maximum value's data type and converts
145 /// null values to the proper maximum value for the data type.
147 /// <param name="max">The maximum value to be processed.</param>
148 /// <returns>The maximum value with appropriate null-converted minimum values.</returns>
149 private object GetMaxValue(object max
)
153 //check properties for valid types
156 case RangeValidationType
.Integer
:
157 return GetIntValue(max
, int.MaxValue
);
158 case RangeValidationType
.Decimal
:
159 return GetDecimalValue(max
, decimal.MaxValue
);
160 case RangeValidationType
.DateTime
:
161 return GetDateTimeValue(max
, DateTime
.MaxValue
);
162 case RangeValidationType
.String
:
163 return (max
== null || String
.IsNullOrEmpty(max
.ToString()) ? String
.Empty
: max
.ToString());
165 throw new ArgumentException("Unknown RangeValidatorType found.");
168 catch(InvalidCastException
)
170 throw new ArgumentException(
171 "RangeValidator's maximum value data type is incompatible with the RangeValidationType specified.");
176 /// Validate that the property value matches the value requirements.
178 /// <param name="instance"></param>
179 /// <param name="fieldValue"></param>
180 /// <returns><c>true</c> if the field is OK</returns>
181 public override bool IsValid(object instance
, object fieldValue
)
183 if ((fieldValue
== null) || (String
.IsNullOrEmpty(fieldValue
.ToString())))
194 case RangeValidationType
.Integer
:
198 intValue
= (int) fieldValue
;
199 valid
= intValue
>= (int) min
&& intValue
<= (int) max
;
203 if (int.TryParse(fieldValue
.ToString(), out intValue
))
205 valid
= intValue
>= (int) min
&& intValue
<= (int) max
;
209 case RangeValidationType
.Decimal
:
210 decimal decimalValue
;
213 decimalValue
= (decimal) fieldValue
;
214 valid
= decimalValue
>= (decimal) min
&& decimalValue
<= (decimal) max
;
218 if (decimal.TryParse(fieldValue
.ToString(), out decimalValue
))
220 valid
= decimalValue
>= (decimal) min
&& decimalValue
<= (decimal) max
;
224 case RangeValidationType
.DateTime
:
228 dtValue
= (DateTime
) fieldValue
;
229 valid
= dtValue
>= (DateTime
) min
&& dtValue
<= (DateTime
) max
;
233 if (DateTime
.TryParse(fieldValue
.ToString(), out dtValue
))
235 valid
= dtValue
>= (DateTime
) min
&& dtValue
<= (DateTime
) max
;
239 case RangeValidationType
.String
:
240 string stringValue
= fieldValue
.ToString();
241 string minv
= min
.ToString();
242 string maxv
= max
.ToString();
244 (String
.IsNullOrEmpty(minv
) ||
245 String
.Compare(stringValue
, minv
, StringComparison
.InvariantCultureIgnoreCase
) >= 0)
247 (String
.IsNullOrEmpty(maxv
) ||
248 String
.Compare(stringValue
, maxv
, StringComparison
.InvariantCultureIgnoreCase
) <= 0)
264 /// Gets a value indicating whether this validator supports browser validation.
267 /// <see langword="true"/> if browser validation is supported; otherwise, <see langword="false"/>.
269 public override bool SupportsBrowserValidation
275 /// Applies the browser validation by setting up one or
276 /// more input rules on <see cref="IBrowserValidationGenerator"/>.
278 /// <param name="config">The config.</param>
279 /// <param name="inputType">Type of the input.</param>
280 /// <param name="generator">The generator.</param>
281 /// <param name="attributes">The attributes.</param>
282 /// <param name="target">The target.</param>
283 public override void ApplyBrowserValidation(BrowserValidationConfiguration config
, InputElementType inputType
,
284 IBrowserValidationGenerator generator
, IDictionary attributes
,
287 base.ApplyBrowserValidation(config
, inputType
, generator
, attributes
, target
);
291 case RangeValidationType
.Integer
:
292 generator
.SetValueRange(target
, (int) min
, (int) max
, BuildErrorMessage());
294 case RangeValidationType
.Decimal
:
295 generator
.SetValueRange(target
, (decimal) min
, (decimal) max
, BuildErrorMessage());
297 case RangeValidationType
.DateTime
:
298 generator
.SetValueRange(target
, (DateTime
) min
, (DateTime
) max
, BuildErrorMessage());
300 case RangeValidationType
.String
:
301 generator
.SetValueRange(target
, (string) min
, (string) max
, BuildErrorMessage());
304 throw new ArgumentOutOfRangeException();
309 /// Builds the error message.
311 /// <returns></returns>
312 protected override string BuildErrorMessage()
314 if (type
== RangeValidationType
.DateTime
)
316 return BuildDateTimeErrorMessage((DateTime
) min
, (DateTime
) max
);
319 if (type
== RangeValidationType
.String
)
321 return BuildStringErrorMessage(min
.ToString(), max
.ToString());
324 if (type
== RangeValidationType
.Integer
)
326 return BuildIntegerErrorMessage((int) min
, (int) max
);
329 if (type
== RangeValidationType
.Decimal
)
331 return BuildDecimalErrorMessage((decimal) min
, (decimal) max
);
334 throw new InvalidOperationException();
338 /// Gets the error message string for Integer validation
340 /// <returns>an error message</returns>
341 protected string BuildIntegerErrorMessage(int min
, int max
)
343 if (min
== int.MinValue
&& max
!= int.MaxValue
)
345 // range against max value only
346 return string.Format(GetString(MessageConstants
.RangeTooHighMessage
), max
);
348 else if (min
!= int.MinValue
&& max
== int.MaxValue
)
350 // range against min value only
351 return string.Format(GetString(MessageConstants
.RangeTooLowMessage
), min
);
353 else if (min
!= int.MinValue
|| max
!= int.MaxValue
)
355 return string.Format(GetString(MessageConstants
.RangeTooHighOrLowMessage
), min
, max
);
359 throw new InvalidOperationException();
364 /// Gets the error message string for Decimal validation
366 /// <returns>an error message</returns>
367 protected string BuildDecimalErrorMessage(decimal min
, decimal max
)
369 if (min
== decimal.MinValue
&& max
!= decimal.MaxValue
)
371 // range against max value only
372 return string.Format(GetString(MessageConstants
.RangeTooHighMessage
), max
);
374 else if (min
!= decimal.MinValue
&& max
== decimal.MaxValue
)
376 // range against min value only
377 return string.Format(GetString(MessageConstants
.RangeTooLowMessage
), min
);
379 else if (min
!= decimal.MinValue
|| max
!= decimal.MaxValue
)
381 return string.Format(GetString(MessageConstants
.RangeTooHighOrLowMessage
), min
, max
);
385 throw new InvalidOperationException();
391 /// Gets the error message string for DateTime validation
393 /// <returns>an error message</returns>
394 protected string BuildDateTimeErrorMessage(DateTime min
, DateTime max
)
396 if (min
== DateTime
.MinValue
&& max
!= DateTime
.MaxValue
)
398 // range against max value only
399 return string.Format(GetString(MessageConstants
.RangeTooHighMessage
), max
);
401 else if (min
!= DateTime
.MinValue
&& max
== DateTime
.MaxValue
)
403 // range against min value only
404 return string.Format(GetString(MessageConstants
.RangeTooLowMessage
), min
);
406 else if (min
!= DateTime
.MinValue
|| max
!= DateTime
.MaxValue
)
408 return string.Format(GetString(MessageConstants
.RangeTooHighOrLowMessage
), min
, max
);
412 throw new InvalidOperationException();
417 /// Gets the error message string for string validation
419 /// <returns>an error message</returns>
420 protected string BuildStringErrorMessage(string min
, string max
)
422 if (String
.IsNullOrEmpty(min
) && !String
.IsNullOrEmpty(max
))
424 // range against max value only
425 return string.Format(GetString(MessageConstants
.RangeTooHighMessage
), max
);
427 else if (!String
.IsNullOrEmpty(min
) && String
.IsNullOrEmpty(max
))
429 // range against min value only
430 return string.Format(GetString(MessageConstants
.RangeTooLowMessage
), min
);
432 else if (!String
.IsNullOrEmpty(min
) || !String
.IsNullOrEmpty(max
))
434 return string.Format(GetString(MessageConstants
.RangeTooHighOrLowMessage
), min
, max
);
438 throw new InvalidOperationException();
443 /// Returns the key used to internationalize error messages
446 protected override string MessageKey
448 get { return MessageConstants.InvalidRangeMessage; }
451 private static void AssertValid(string max
, string min
)
453 if (String
.IsNullOrEmpty(min
) && String
.IsNullOrEmpty(max
))
455 throw new ArgumentException(
456 "Both min and max were set in such as way that neither would be tested. At least one must be tested.");
460 private static void AssertValid(int max
, int min
)
462 if (min
== int.MinValue
&& max
== int.MaxValue
)
464 throw new ArgumentException(
465 "Both min and max were set in such as way that neither would be tested. At least one must be tested.");
469 throw new ArgumentException("The min parameter must be less than or equal to the max parameter.");
473 throw new ArgumentException("The max parameter must be greater than or equal to the min parameter.");
477 private static void AssertValid(decimal max
, decimal min
)
479 if (min
== decimal.MinValue
&& max
== decimal.MaxValue
)
481 throw new ArgumentException(
482 "Both min and max were set in such as way that neither would be tested. At least one must be tested.");
486 throw new ArgumentException("The min parameter must be less than or equal to the max parameter.");
490 throw new ArgumentException("The max parameter must be greater than or equal to the min parameter.");
494 private static void AssertValid(DateTime max
, DateTime min
)
496 if (min
== DateTime
.MinValue
&& max
== DateTime
.MaxValue
)
498 throw new ArgumentException(
499 "Both min and max were set in such as way that neither would be tested. At least one must be tested.");
503 throw new ArgumentException("The min parameter must be less than or equal to the max parameter.");
507 throw new ArgumentException("The max parameter must be greater than or equal to the min parameter.");
512 /// Internal method that checks a given minimum value's data type and converts
513 /// null values to the proper minimum value for the data type.
515 /// <param name="min">The minimum value to be processed.</param>
516 /// <returns>The minimum value with appropriate null-converted minimum values.</returns>
517 private object GetMinValue(object min
)
521 //check properties for valid types
524 case RangeValidationType
.Integer
:
525 return GetIntValue(min
, int.MinValue
);
526 case RangeValidationType
.Decimal
:
527 return GetDecimalValue(min
, decimal.MinValue
);
528 case RangeValidationType
.DateTime
:
529 return GetDateTimeValue(min
, DateTime
.MinValue
);
530 case RangeValidationType
.String
:
531 return (min
== null || String
.IsNullOrEmpty(min
.ToString()) ? String
.Empty
: min
.ToString());
533 throw new ArgumentException("Unknown RangeValidatorType found.");
536 catch(InvalidCastException
)
538 throw new ArgumentException(
539 "RangeValidator's mininum value data type is incompatible with the RangeValidationType specified.");
543 private int GetIntValue(object value, int defaultValue
)
545 int intValue
= defaultValue
;
548 intValue
= (int) value;
552 if (value == null || !int.TryParse(value.ToString(), out intValue
))
553 value = defaultValue
;
558 private decimal GetDecimalValue(object value, decimal defaultValue
)
560 decimal decimalValue
= defaultValue
;
561 if (value == null || !decimal.TryParse(value.ToString(), out decimalValue
))
562 value = defaultValue
;
566 private DateTime
GetDateTimeValue(object value, DateTime defaultValue
)
568 DateTime dtValue
= defaultValue
;
571 dtValue
= (DateTime
) value;
575 if (value == null || !DateTime
.TryParse(value.ToString(), out dtValue
))
576 value = defaultValue
;