예제 #1
0
        private ValidatorDefinition ExtractValidatorDefinition(Type type)
        {
            var rules = typeValidationRuleBuilder.Build(type, "");

            if (!rules.Any())
            {
                return(null);
            }
            var ruleset = rules.Aggregate((a, b) => a + "; " + b);

            return(new ValidatorDefinition(DataApiClient.GetCollectionName(type), ValidatorType.TextRules, ruleset));
        }
예제 #2
0
        public List <string> Build(PropertyInfo property, string parentPath)
        {
            var propertyRules = new List <string>();
            var propertyName  = property.Name;
            var propertyPath  = string.IsNullOrEmpty(parentPath) ? propertyName : $"{parentPath}.{propertyName}";
            var propertyType  = property.PropertyType;
            var dataTypeRule  = BuildDataTypeRule(propertyPath, propertyType);

            if (dataTypeRule != null)
            {
                propertyRules.Add(dataTypeRule);
            }
            var validationAttributes = property.GetCustomAttributes <ValidationAttribute>().ToList();
            var isOptional           = !validationAttributes.Select(x => x.GetType())
                                       .Intersect(
                new[]
            {
                typeof(RequiredAttribute),
                typeof(RequiredIfPropertyEqualToAttribute),
                typeof(RequiredIfPropertyNotEqualToAttribute)
            }).Any();

            foreach (var validationAttribute in validationAttributes)
            {
                string rule = null;
                switch (validationAttribute)
                {
                case ItemCountAttribute itemCountAttribute:
                    rule = BuildItemCountRule(propertyPath, itemCountAttribute);
                    break;

                case LessThanAttribute lessThanAttribute:
                    rule = BuildLessThan(propertyPath, lessThanAttribute);
                    break;

                case NotEmptyAttribute notEmptyAttribute:
                    rule = BuildNotEmptyRule(propertyPath);
                    break;

                case RangeOrNaNAttribute rangeOrNaNAttribute:
                    rule = BuildRangeRule(propertyPath, rangeOrNaNAttribute, allowNaN: true);
                    break;

                case RequiredIfPropertyEqualToAttribute requiredIfPropertyHasValueAttribute:
                    rule = BuildRequiredIfPropertyHasValueRule(propertyPath, requiredIfPropertyHasValueAttribute);
                    break;

                case RequiredIfPropertyNotEqualToAttribute requiredIfPropertyNotHasValueAttribute:
                    rule = BuildRequiredIfPropertyNotHasValueRule(propertyPath, requiredIfPropertyNotHasValueAttribute);
                    break;

                case DataReferenceAttribute dataReferenceAttribute:
                    rule = BuildDataReferenceRule(propertyPath, dataReferenceAttribute);
                    break;

                case GreaterThanAttribute greaterThanAttribute:
                    rule = BuildGreaterThan(propertyPath, greaterThanAttribute);
                    break;

                case EmailAddressAttribute emailAddressAttribute:
                    rule = BuildRegularExpressionRule(propertyPath, new RegularExpressionAttribute("^[a-zA-Z0-9\\._-]+@[a-zA-Z0-9\\._-]+\\.[a-zA-Z0-9]+$"));
                    break;

                case EnumDataTypeAttribute enumDataTypeAttribute:
                    if (enumDataTypeAttribute.CustomDataType != null)
                    {
                        propertyType = Assembly.GetAssembly(typeof(IId)).GetTypes()
                                       .Where(t => t.IsEnum)
                                       .SingleOrDefault(t => t.Name == enumDataTypeAttribute.CustomDataType);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    break;

                case UrlAttribute urlAttribute:
                    rule = BuildRegularExpressionRule(propertyPath, new RegularExpressionAttribute("^https?://.+$"));
                    break;

                case DataTypeAttribute dataTypeAttribute:
                    if (dataTypeAttribute.CustomDataType != null)
                    {
                        propertyType = Assembly.GetAssembly(typeof(IId)).GetTypes()
                                       .SingleOrDefault(t => t.Name == dataTypeAttribute.CustomDataType);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    break;

                case MaxLengthAttribute maxLengthAttribute:
                    if (propertyType == typeof(string))
                    {
                        rule = BuildStringLengthRule(propertyPath, new StringLengthAttribute(maxLengthAttribute.Length));
                    }
                    else if (propertyType.IsInstanceOfType(typeof(IList)))
                    {
                        rule = BuildItemCountRule(propertyPath, new ItemCountAttribute(0, maxLengthAttribute.Length));
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    break;

                case MinLengthAttribute minLengthAttribute:
                    if (propertyType == typeof(string))
                    {
                        rule = BuildMinimumStringLengthRule(propertyPath, minLengthAttribute);
                    }
                    else if (propertyType.IsInstanceOfType(typeof(IList)))
                    {
                        rule = BuildMinimumItemsCountRule(propertyPath, minLengthAttribute);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    break;

                case RangeAttribute rangeAttribute:
                    rule = BuildRangeRule(propertyPath, rangeAttribute);
                    break;

                case RegularExpressionAttribute regularExpressionAttribute:
                    rule = BuildRegularExpressionRule(propertyPath, regularExpressionAttribute);
                    break;

                case RequiredAttribute requiredAttribute:
                    rule = BuildExistsRule(propertyPath);
                    break;

                case StringLengthAttribute stringLengthAttribute:
                    rule = BuildStringLengthRule(propertyPath, stringLengthAttribute);
                    break;
                }

                if (rule == null)
                {
                    continue;
                }
                if (isOptional)
                {
                    rule += $" IF {BuildExistsRule(propertyPath)}";
                }

                propertyRules.Add(rule);
            }

            // Recurse to child-properties
            if (propertyType != null &&
                !propertyType.IsPrimitive &&
                propertyPath.Count(c => c == '.') + 1 < maximumPathDepth)
            {
                var stringSerializedTypes = new [] { typeof(string), typeof(DateTime), typeof(DateTime?), typeof(TimeSpan), typeof(TimeSpan?), typeof(UnitValue) };
                if (typeof(IDictionary).IsAssignableFrom(propertyType))
                {
                    // Do nothing
                }
                else if (typeof(IList).IsAssignableFrom(propertyType))
                {
                    var itemType = propertyType.IsArray
                        ? propertyType.GetElementType()
                        : propertyType.GenericTypeArguments.SingleOrDefault();
                    if (itemType != null && !itemType.InSet(stringSerializedTypes))
                    {
                        propertyRules.AddRange(typeValidationRuleBuilder.Build(itemType, propertyPath));
                    }
                }
                else if (propertyType.InSet(stringSerializedTypes)) // These are serialized to string without further hierarchy
                {
                    // Go no deeper
                }
                else
                {
                    foreach (var childProperty in property.PropertyType.GetProperties())
                    {
                        propertyRules.AddRange(Build(childProperty, propertyPath));
                    }
                }
            }

            return(propertyRules);
        }