RangeIfIdsInAttribute.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Globalization;
  6. using System.ComponentModel;
  7. using System.ComponentModel.DataAnnotations;
  8. using System.Web.Mvc;
  9. namespace Bowin.Common.Mvc
  10. {
  11. [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  12. public class RangeIfIdsInAttribute : ValidationAttribute, IClientValidatable
  13. {
  14. private const string DefaultErrorMessage = "字段 {0} 必须在 {1} 和 {2} 之间。";
  15. private const string Template = "$-{0}-$";
  16. private RangeIfIdsInAttribute(string otherProperty, string[] ids)
  17. : base(DefaultErrorMessage)
  18. {
  19. if (string.IsNullOrEmpty(otherProperty))
  20. {
  21. throw new ArgumentNullException("otherProperty");
  22. }
  23. if (ids == null || ids.Length == 0)
  24. {
  25. throw new ArgumentNullException("ids");
  26. }
  27. OtherProperty = otherProperty;
  28. StringBuilder sb = new StringBuilder();
  29. foreach (var item in ids)
  30. {
  31. sb.AppendFormat(string.Format("{0},", Template), item);
  32. }
  33. Ids = sb.ToString().TrimEnd(',').ToLower();
  34. }
  35. public RangeIfIdsInAttribute(int minimum, int maximum, string otherProperty, string[] ids)
  36. : this(otherProperty, ids)
  37. {
  38. this.Minimum = minimum;
  39. this.Maximum = maximum;
  40. this.OperandType = typeof(int);
  41. }
  42. public RangeIfIdsInAttribute(double minimum, double maximum, string otherProperty, string[] ids)
  43. : this(otherProperty, ids)
  44. {
  45. this.Minimum = minimum;
  46. this.Maximum = maximum;
  47. this.OperandType = typeof(double);
  48. }
  49. public string OtherProperty { get; private set; }
  50. public object Minimum { get; private set; }
  51. public object Maximum { get; private set; }
  52. public string Ids { get; private set; }
  53. public Type OperandType { get; private set; }
  54. private Func<object, object> Conversion { get; set; }
  55. public static string FormatPropertyForClientValidation(string property)
  56. {
  57. if (property == null)
  58. {
  59. throw new ArgumentException("属性值不能为空!", "property");
  60. }
  61. return ("*." + property);
  62. }
  63. public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
  64. {
  65. var clientValidationRule = new ModelClientValidationRule()
  66. {
  67. ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
  68. ValidationType = "rangeifidsin"
  69. };
  70. clientValidationRule.ValidationParameters.Add("otherproperty", FormatPropertyForClientValidation(OtherProperty));
  71. clientValidationRule.ValidationParameters.Add("ids", Ids);
  72. clientValidationRule.ValidationParameters.Add("minimum", Minimum);
  73. clientValidationRule.ValidationParameters.Add("maximum", Maximum);
  74. clientValidationRule.ValidationParameters.Add("template", Template);
  75. return new[] { clientValidationRule };
  76. }
  77. public override string FormatErrorMessage(string name)
  78. {
  79. this.SetupConversion();
  80. return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, new object[] { name, Minimum, Maximum });
  81. }
  82. protected override ValidationResult IsValid(object value, ValidationContext validationContext)
  83. {
  84. if (value == null) return ValidationResult.Success;
  85. this.SetupConversion();
  86. var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(OtherProperty);
  87. var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
  88. if (otherPropertyValue == null) return ValidationResult.Success;
  89. var otherPropertyLowerValue = otherPropertyValue.ToString().ToLower();
  90. if (!Ids.Contains(otherPropertyLowerValue)) return ValidationResult.Success;
  91. object obj2 = null;
  92. try
  93. {
  94. obj2 = this.Conversion(value);
  95. }
  96. catch (FormatException)
  97. {
  98. return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
  99. }
  100. catch (InvalidCastException)
  101. {
  102. return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
  103. }
  104. catch (NotSupportedException)
  105. {
  106. return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
  107. }
  108. IComparable minimum = (IComparable)this.Minimum;
  109. IComparable maximum = (IComparable)this.Maximum;
  110. if ((minimum.CompareTo(obj2) <= 0) && (maximum.CompareTo(obj2) >= 0))
  111. {
  112. return ValidationResult.Success;
  113. }
  114. else
  115. {
  116. return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
  117. }
  118. }
  119. private void SetupConversion()
  120. {
  121. if (this.Conversion == null)
  122. {
  123. object minimum = this.Minimum;
  124. object maximum = this.Maximum;
  125. if ((minimum == null) || (maximum == null))
  126. {
  127. throw new InvalidOperationException("必须设置最大值和最小值。");
  128. }
  129. Type type = minimum.GetType();
  130. if (type == typeof(int))
  131. {
  132. this.Initialize((int)minimum, (int)maximum, v => Convert.ToInt32(v, CultureInfo.InvariantCulture));
  133. }
  134. else if (type == typeof(double))
  135. {
  136. this.Initialize((double)minimum, (double)maximum, v => Convert.ToDouble(v, CultureInfo.InvariantCulture));
  137. }
  138. else
  139. {
  140. type = this.OperandType;
  141. if (type == null)
  142. {
  143. throw new InvalidOperationException("必须设置操作类型。");
  144. }
  145. Type type2 = typeof(IComparable);
  146. if (!type2.IsAssignableFrom(type))
  147. {
  148. throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "类型 {0} 和类型 {1} 不支持比较运算。", new object[] { type.FullName, type2.FullName }));
  149. }
  150. TypeConverter converter = TypeDescriptor.GetConverter(type);
  151. IComparable comparable = (IComparable)converter.ConvertFromString((string)minimum);
  152. IComparable comparable2 = (IComparable)converter.ConvertFromString((string)maximum);
  153. Func<object, object> conversion = delegate(object value)
  154. {
  155. if ((value != null) && (value.GetType() == type))
  156. {
  157. return value;
  158. }
  159. return converter.ConvertFrom(value);
  160. };
  161. this.Initialize(comparable, comparable2, conversion);
  162. }
  163. }
  164. }
  165. private void Initialize(IComparable minimum, IComparable maximum, Func<object, object> conversion)
  166. {
  167. if (minimum.CompareTo(maximum) > 0)
  168. {
  169. throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "最小值 {0} 必须小于最大值 {1} 。", new object[] { maximum, minimum }));
  170. }
  171. this.Minimum = minimum;
  172. this.Maximum = maximum;
  173. this.Conversion = conversion;
  174. }
  175. }
  176. }