using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text.RegularExpressions; namespace Edge.Core.Parser.BinaryParser.Attributes { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] public class RangeAttribute : ValidationAttribute { /// /// default have 3 types of validation, the value based on 0, if need extend, then increase the value /// private int rangValidationType = -1; private string errorMsg = string.Empty; private string validatedValue = string.Empty; private int intMin = -1; private int intMax = -1; private decimal decimalMin = -1; private decimal decimalMax = -1; private IEnumerable allowedIntValues = null; //private Type validatingType = null; private string regexString = string.Empty; private RegexOptions regexOptions; /// /// Range validation for int type values with specify the min and max value. /// /// min values /// max values /// error message to show, support String.Format, the {0}, {1} and {2} are auto set to actual value, min and max. public RangeAttribute(int min, int max, string errorMessage) { this.intMin = min; this.intMax = max; this.errorMsg = errorMessage; this.rangValidationType = 0; } /// /// Range validation for decimal type values with specify the min and max value. /// /// /// /// error message to show, support String.Format, the {0}, {1} and {2} are auto set to concrete value, min and max. public RangeAttribute(decimal min, decimal max, string errorMessage) { this.decimalMin = min; this.decimalMax = max; this.errorMsg = errorMessage; this.rangValidationType = 1; } /// /// Range validation for string type values with specify the regex constrait. /// /// /// error message to show, support String.Format, the {0}, {1} are auto set to concrete value, regexString. public RangeAttribute(string regexString, RegexOptions regexOptions, string errorMessage) { //this.validatingType = type; this.regexString = regexString; this.regexOptions = regexOptions; this.errorMsg = errorMessage; this.rangValidationType = 2; } /// /// Range validation for int type values with specify allowed values. /// /// the value must be the element of the array: allowedValues /// error message to show, support String.Format, the {0}, {1} are auto set to concrete value, allowed ints string. public RangeAttribute(int[] allowedValues, string errorMessage) { this.allowedIntValues = allowedValues; this.errorMsg = errorMessage; this.rangValidationType = 3; } public new string ErrorMessage { get { switch (this.rangValidationType) { case 0: return string.Format(this.errorMsg, this.validatedValue, this.intMin, this.intMax); case 1: return string.Format(this.errorMsg, this.validatedValue, this.decimalMin, this.decimalMax); case 2: return string.Format(this.errorMsg, this.validatedValue, this.regexString); case 3: return string.Format(this.errorMsg, this.validatedValue, this.allowedIntValues.Cast().Aggregate((p, acc) => p + ", " + acc)); } return this.errorMsg; } //private set { this.errorMsg = value; } } public override bool IsValid(object value) { if (value == null) return true; this.validatedValue = value?.ToString() ?? ""; switch (this.rangValidationType) { case 0: int targetInt = -1; if (!int.TryParse(value.ToString(), out targetInt)) { return false; } return targetInt >= this.intMin && targetInt <= this.intMax; case 1: decimal targetDecimal = -1; if (!decimal.TryParse(value.ToString(), out targetDecimal)) { return false; } return targetDecimal >= this.decimalMin && targetDecimal <= this.decimalMax; case 2: return Regex.IsMatch(value.ToString(), this.regexString, this.regexOptions); case 3: int tempInt = -1; if (!int.TryParse(value.ToString(), out tempInt)) { return false; } return this.allowedIntValues.Contains(tempInt); } return false; } } }