using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Web.Mvc; namespace Bowin.Common.Mvc { [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class RangeIfIdsInAttribute : ValidationAttribute, IClientValidatable { private const string DefaultErrorMessage = "字段 {0} 必须在 {1} 和 {2} 之间。"; private const string Template = "$-{0}-$"; private RangeIfIdsInAttribute(string otherProperty, string[] ids) : base(DefaultErrorMessage) { if (string.IsNullOrEmpty(otherProperty)) { throw new ArgumentNullException("otherProperty"); } if (ids == null || ids.Length == 0) { throw new ArgumentNullException("ids"); } OtherProperty = otherProperty; StringBuilder sb = new StringBuilder(); foreach (var item in ids) { sb.AppendFormat(string.Format("{0},", Template), item); } Ids = sb.ToString().TrimEnd(',').ToLower(); } public RangeIfIdsInAttribute(int minimum, int maximum, string otherProperty, string[] ids) : this(otherProperty, ids) { this.Minimum = minimum; this.Maximum = maximum; this.OperandType = typeof(int); } public RangeIfIdsInAttribute(double minimum, double maximum, string otherProperty, string[] ids) : this(otherProperty, ids) { this.Minimum = minimum; this.Maximum = maximum; this.OperandType = typeof(double); } public string OtherProperty { get; private set; } public object Minimum { get; private set; } public object Maximum { get; private set; } public string Ids { get; private set; } public Type OperandType { get; private set; } private Func Conversion { get; set; } public static string FormatPropertyForClientValidation(string property) { if (property == null) { throw new ArgumentException("属性值不能为空!", "property"); } return ("*." + property); } public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var clientValidationRule = new ModelClientValidationRule() { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "rangeifidsin" }; clientValidationRule.ValidationParameters.Add("otherproperty", FormatPropertyForClientValidation(OtherProperty)); clientValidationRule.ValidationParameters.Add("ids", Ids); clientValidationRule.ValidationParameters.Add("minimum", Minimum); clientValidationRule.ValidationParameters.Add("maximum", Maximum); clientValidationRule.ValidationParameters.Add("template", Template); return new[] { clientValidationRule }; } public override string FormatErrorMessage(string name) { this.SetupConversion(); return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, new object[] { name, Minimum, Maximum }); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value == null) return ValidationResult.Success; this.SetupConversion(); var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(OtherProperty); var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null); if (otherPropertyValue == null) return ValidationResult.Success; var otherPropertyLowerValue = otherPropertyValue.ToString().ToLower(); if (!Ids.Contains(otherPropertyLowerValue)) return ValidationResult.Success; object obj2 = null; try { obj2 = this.Conversion(value); } catch (FormatException) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } catch (InvalidCastException) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } catch (NotSupportedException) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } IComparable minimum = (IComparable)this.Minimum; IComparable maximum = (IComparable)this.Maximum; if ((minimum.CompareTo(obj2) <= 0) && (maximum.CompareTo(obj2) >= 0)) { return ValidationResult.Success; } else { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } private void SetupConversion() { if (this.Conversion == null) { object minimum = this.Minimum; object maximum = this.Maximum; if ((minimum == null) || (maximum == null)) { throw new InvalidOperationException("必须设置最大值和最小值。"); } Type type = minimum.GetType(); if (type == typeof(int)) { this.Initialize((int)minimum, (int)maximum, v => Convert.ToInt32(v, CultureInfo.InvariantCulture)); } else if (type == typeof(double)) { this.Initialize((double)minimum, (double)maximum, v => Convert.ToDouble(v, CultureInfo.InvariantCulture)); } else { type = this.OperandType; if (type == null) { throw new InvalidOperationException("必须设置操作类型。"); } Type type2 = typeof(IComparable); if (!type2.IsAssignableFrom(type)) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "类型 {0} 和类型 {1} 不支持比较运算。", new object[] { type.FullName, type2.FullName })); } TypeConverter converter = TypeDescriptor.GetConverter(type); IComparable comparable = (IComparable)converter.ConvertFromString((string)minimum); IComparable comparable2 = (IComparable)converter.ConvertFromString((string)maximum); Func conversion = delegate(object value) { if ((value != null) && (value.GetType() == type)) { return value; } return converter.ConvertFrom(value); }; this.Initialize(comparable, comparable2, conversion); } } } private void Initialize(IComparable minimum, IComparable maximum, Func conversion) { if (minimum.CompareTo(maximum) > 0) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "最小值 {0} 必须小于最大值 {1} 。", new object[] { maximum, minimum })); } this.Minimum = minimum; this.Maximum = maximum; this.Conversion = conversion; } } }