private void ApplyRulesToSchema(OpenApiSchema schema, SchemaFilterContext context, IValidator validator)
        {
            var lazyLog = new LazyLog(_logger,
                                      logger => logger.LogDebug($"Applying FluentValidation rules to swagger schema for type '{context.Type}'."));

            foreach (var schemaPropertyName in schema?.Properties?.Keys ?? Array.Empty <string>())
            {
                var validators = validator.GetValidatorsForMemberIgnoreCase(schemaPropertyName);

                foreach (var propertyValidator in validators)
                {
                    foreach (var rule in _rules)
                    {
                        if (rule.Matches(propertyValidator))
                        {
                            try
                            {
                                lazyLog.LogOnce();
                                rule.Apply(new RuleContext(schema, context, schemaPropertyName, propertyValidator));
                                _logger.LogDebug($"Rule '{rule.Name}' applied for property '{context.Type.Name}.{schemaPropertyName}'");
                            }
                            catch (Exception e)
                            {
                                _logger.LogWarning(0, e, $"Error on apply rule '{rule.Name}' for property '{context.Type.Name}.{schemaPropertyName}'.");
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Applies rules from validator.
        /// </summary>
        internal static void ApplyRulesToSchema(
            OpenApiSchema schema,
            Type schemaType,
            IEnumerable <string>?schemaPropertyNames,
            SchemaFilterContext?schemaFilterContext,
            IValidator validator,
            IReadOnlyCollection <FluentValidationRule> rules,
            ILogger logger)
        {
            var schemaTypeName = schemaType.Name;

            var lazyLog = new LazyLog(logger,
                                      l => l.LogDebug($"Applying FluentValidation rules to swagger schema '{schemaTypeName}'."));

            schemaPropertyNames ??= schema.Properties?.Keys ?? Array.Empty <string>();
            foreach (var schemaPropertyName in schemaPropertyNames)
            {
                var validationRules = validator.GetValidationRulesForMemberIgnoreCase(schemaPropertyName).ToArrayDebug();

                foreach (var ruleContext in validationRules)
                {
                    var propertyValidators = ruleContext.PropertyRule.Validators;
                    foreach (var propertyValidator in propertyValidators)
                    {
                        foreach (var rule in rules)
                        {
                            if (rule.Matches(propertyValidator))
                            {
                                try
                                {
                                    var ruleHistoryItem = new RuleHistoryCache.RuleHistoryItem(schemaTypeName, schemaPropertyName, propertyValidator, rule.Name);
                                    if (!schema.ContainsRuleHistoryItem(ruleHistoryItem))
                                    {
                                        lazyLog.LogOnce();

                                        rule.Apply(new RuleContext(schema, schemaPropertyName, propertyValidator, schemaFilterContext, isCollectionValidator: ruleContext.IsCollectionRule));

                                        logger.LogDebug($"Rule '{rule.Name}' applied for property '{schemaTypeName}.{schemaPropertyName}'.");
                                        schema.AddRuleHistoryItem(ruleHistoryItem);
                                    }
                                    else
                                    {
                                        logger.LogDebug($"Rule '{rule.Name}' already applied for property '{schemaTypeName}.{schemaPropertyName}'.");
                                    }
                                }
                                catch (Exception e)
                                {
                                    logger.LogWarning(0, e, $"Error on apply rule '{rule.Name}' for property '{schemaTypeName}.{schemaPropertyName}'.");
                                }
                            }
                        }
                    }
                }
            }
        }
Example #3
0
        void ApplyInternal(Operation operation, OperationFilterContext context)
        {
            if (operation.Parameters == null)
            {
                return;
            }

            var schemaIdSelector = _swaggerGenOptions.SchemaRegistryOptions.SchemaIdSelector ?? new SchemaRegistryOptions().SchemaIdSelector;

            foreach (var operationParameter in operation.Parameters)
            {
                var apiParameterDescription = context.ApiDescription.ParameterDescriptions.FirstOrDefault(description =>
                                                                                                          description.Name.Equals(operationParameter.Name, StringComparison.InvariantCultureIgnoreCase));

                var modelMetadata = apiParameterDescription?.ModelMetadata;
                if (modelMetadata != null)
                {
                    var parameterType = modelMetadata.ContainerType;
                    if (parameterType == null)
                    {
                        continue;
                    }
                    var validator = _validatorFactory.GetValidator(parameterType);
                    if (validator == null)
                    {
                        continue;
                    }

                    var key = modelMetadata.PropertyName;
                    var validatorsForMember = validator.GetValidatorsForMemberIgnoreCase(key);

                    var lazyLog = new LazyLog(_logger,
                                              logger => logger.LogDebug($"Applying FluentValidation rules to swagger schema for type '{parameterType}' from operation '{operation.OperationId}'."));

                    Schema schema = null;
                    foreach (var propertyValidator in validatorsForMember)
                    {
                        foreach (var rule in _rules)
                        {
                            if (rule.Matches(propertyValidator))
                            {
                                try
                                {
                                    var schemaId = schemaIdSelector(parameterType);

                                    if (!context.SchemaRegistry.Definitions.TryGetValue(schemaId, out schema))
                                    {
                                        schema = context.SchemaRegistry.GetOrRegister(parameterType);
                                    }

                                    if (schema.Properties == null && context.SchemaRegistry.Definitions.ContainsKey(schemaId))
                                    {
                                        schema = context.SchemaRegistry.Definitions[schemaId];
                                    }

                                    if (schema.Properties != null && schema.Properties.Count > 0)
                                    {
                                        lazyLog.LogOnce();
                                        rule.Apply(new RuleContext(schema, new SchemaFilterContext(parameterType, null, context.SchemaRegistry), key.ToLowerCamelCase(), propertyValidator));
                                        _logger.LogDebug($"Rule '{rule.Name}' applied for property '{parameterType.Name}.{key}'.");
                                    }
                                    else
                                    {
                                        _logger.LogDebug($"Rule '{rule.Name}' skipped for property '{parameterType.Name}.{key}'.");
                                    }
                                }
                                catch (Exception e)
                                {
                                    _logger.LogWarning(0, e, $"Error on apply rule '{rule.Name}' for property '{parameterType.Name}.{key}'.");
                                }
                            }
                        }
                    }

                    if (schema?.Required != null)
                    {
                        operationParameter.Required = schema.Required.Contains(key, StringComparer.InvariantCultureIgnoreCase);
                    }

                    if (schema?.Properties != null)
                    {
                        var parameterSchema = operationParameter as PartialSchema;
                        if (operationParameter != null)
                        {
                            if (schema.Properties.TryGetValue(key.ToLowerCamelCase(), out var property) ||
                                schema.Properties.TryGetValue(key, out property))
                            {
                                parameterSchema.MinLength        = property.MinLength;
                                parameterSchema.MaxLength        = property.MaxLength;
                                parameterSchema.Pattern          = property.Pattern;
                                parameterSchema.Minimum          = property.Minimum;
                                parameterSchema.Maximum          = property.Maximum;
                                parameterSchema.ExclusiveMaximum = property.ExclusiveMaximum;
                                parameterSchema.ExclusiveMinimum = property.ExclusiveMinimum;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Applies rules from validator.
        /// </summary>
        internal static void ApplyRulesToSchema(
            Type schemaType,
            IEnumerable <string>?schemaPropertyNames,
            IValidator validator,
            ILogger logger,
            SchemaGenerationContext schemaGenerationContext)
        {
            OpenApiSchema schema         = schemaGenerationContext.Schema;
            var           schemaTypeName = schemaType.Name;

            var lazyLog = new LazyLog(logger, l => l.LogDebug($"Applying FluentValidation rules to swagger schema '{schemaTypeName}'."));

            var validationRules = validator
                                  .GetValidationRules()
                                  .Where(context => context.ReflectionContext != null)
                                  .ToArray();

            schemaPropertyNames ??= schema.Properties?.Keys ?? Array.Empty <string>();
            foreach (var schemaPropertyName in schemaPropertyNames)
            {
                ValidationRuleInfo?validationRuleInfo = validationRules
                                                        .FirstOrDefault(propertyRule => IsMatchesRule(propertyRule, schemaPropertyName, schemaGenerationContext.SchemaGenerationSettings));

                if (validationRuleInfo != null)
                {
                    var propertyValidators = validationRuleInfo.PropertyRule.GetValidators();

                    foreach (var propertyValidator in propertyValidators)
                    {
                        foreach (var rule in schemaGenerationContext.Rules)
                        {
                            if (rule.IsMatches(propertyValidator))
                            {
                                try
                                {
                                    var ruleHistoryItem = new RuleHistoryCache.RuleHistoryItem(schemaTypeName, schemaPropertyName, propertyValidator, rule.Name);
                                    if (!schema.ContainsRuleHistoryItem(ruleHistoryItem))
                                    {
                                        lazyLog.LogOnce();

                                        var ruleContext = new RuleContext(
                                            schema: schema,
                                            propertyKey: schemaPropertyName,
                                            validationRuleInfo: validationRuleInfo,
                                            propertyValidator: propertyValidator,
                                            reflectionContext: validationRuleInfo.ReflectionContext);
                                        rule.Apply(ruleContext);

                                        logger.LogDebug($"Rule '{rule.Name}' applied for property '{schemaTypeName}.{schemaPropertyName}'.");
                                        schema.AddRuleHistoryItem(ruleHistoryItem);
                                    }
                                    else
                                    {
                                        logger.LogDebug($"Rule '{rule.Name}' already applied for property '{schemaTypeName}.{schemaPropertyName}'.");
                                    }
                                }
                                catch (Exception e)
                                {
                                    logger.LogWarning(0, e, $"Error on apply rule '{rule.Name}' for property '{schemaTypeName}.{schemaPropertyName}'.");
                                }
                            }
                        }
                    }
                }
            }
        }