private DryvCompiledRule Translate(DryvCompiledRule rule, ITranslator translator) { if (rule.TranslatedValidationExpression != null || rule.TranslationError != null) { return(rule); } try { var translatedRule = translator.Translate(rule.ValidationExpression, rule.PropertyExpression); rule.TranslatedValidationExpression = translatedRule.Factory; rule.PreevaluationOptionTypes = translatedRule.OptionTypes; rule.CodeTemplate = translatedRule.CodeTemplate; } catch (DryvException ex) { switch (this.options.TranslationErrorBehavior) { case TranslationErrorBehavior.ValidateOnServer: rule.TranslatedValidationExpression = null; rule.PreevaluationOptionTypes = null; rule.TranslationError = ex; break; default: throw; } } return(rule); }
private string GetTranslationFromRule(DryvCompiledRule rule, object[] preevaluationOptions) { try { return(rule.TranslatedValidationExpression(this.serviceProvider, preevaluationOptions)); } catch (NullReferenceException ex) { var p = rule.ValidationExpression.Parameters; var parameters = preevaluationOptions.Select((o, i) => new { o, i }).Where(x => x.o == null).Select(x => $"'{p[x.i].Name}'").ToList(); var msg = parameters.Count switch { 0 => "An error occurred while translating the validation rule.", 1 => $"The injected rule parameter {parameters.First()} is null.", _ => $"An injected rule parameter is null. Possible candidates are {string.Join(", ", parameters)}." }; throw CreateException(msg, ex, rule); } catch (Exception ex) { throw CreateException("An error occurred while translating validation rule.", ex, rule); } }
private static void EnsurePreevaluationOptionTypes(DryvCompiledRule rule) { if (rule.PreevaluationOptionTypes?.Any() != true) { rule.PreevaluationOptionTypes = (from p in rule.ValidationExpression.Parameters.Skip(1) select p.Type).ToArray(); } }
public bool IsEnabled(DryvCompiledRule rule, Func <Type, object> objectFactory) { Compile(rule); var options = GetPreevaluationOptions(rule, objectFactory); return(rule.CompiledEnablingExpression(options)); }
private static void Compile(DryvCompiledRule rule) { if (rule.CompiledValidationExpression != null) { return; } rule.CompiledValidationExpression = CompileValidationExpression(rule); rule.CompiledEnablingExpression = CompileEnablingExpression(rule); }
private static object[] GetPreevaluationOptions(DryvCompiledRule rule, Func <Type, object> objectFactory) { foreach (var optionType in rule.PreevaluationOptionTypes) { var options = objectFactory(optionType); if (options == null) { throw new DryvPreevalutationResolvingException($"Could not resolve type '{optionType.FullName}' for rule pre-evaluation."); } } return((from t in rule.PreevaluationOptionTypes select objectFactory(t)).ToArray()); }
public Task <DryvResultMessage> ValidateAsync(DryvCompiledRule rule, object model, Func <Type, object> objectFactory) { Compile(rule); var options = GetPreevaluationOptions(rule, objectFactory); var result = rule.CompiledValidationExpression(model, options); switch (result) { case DryvResultMessage dryvResult: return(Task.FromResult(dryvResult)); case Task <DryvResultMessage> task: return(task); default: throw new InvalidOperationException($"Compiled validation expression for property {rule.Property.DeclaringType.FullName}.{rule.Property.Name} should return '{result.GetType().FullName}'. Only DryvResultMessage and Task<DryvResultMessage> are allowed."); } }
public bool IsDisabled(DryvCompiledRule rule, object model, Func <Type, object> objectFactory) { if (rule.ValidationExpression.ReturnType != typeof(bool)) { return(false); } Compile(rule); var options = GetPreevaluationOptions(rule, objectFactory); try { return((bool)rule.CompiledValidationExpression(model, options)); } catch (Exception ex) { throw new DryvValidationExecutionException(rule, ex); } }
public DryvResultMessage Validate(DryvCompiledRule rule, object model, Func <Type, object> objectFactory) { if (typeof(Task).IsAssignableFrom(rule.ValidationExpression.ReturnType)) { return(DryvResultMessage.Success); } Compile(rule); var options = GetPreevaluationOptions(rule, objectFactory); try { return((DryvResultMessage)rule.CompiledValidationExpression(model, options)); } catch (Exception ex) { throw new DryvValidationExecutionException(rule, ex); } }
private static Func <object, object[], object> CompileValidationExpression(DryvCompiledRule rule) { var lambdaExpression = rule.ValidationExpression; EnsurePreevaluationOptionTypes(rule); var modelParameter = Expression.Parameter(typeof(object), "model"); var optionsParameter = Expression.Parameter(typeof(object[]), "options"); var invokeArguments = new List <Expression> { Expression.Convert(modelParameter, lambdaExpression.Parameters.First().Type) }; AddOptionParameters(invokeArguments, lambdaExpression, optionsParameter, 1); var invokeExpression = Expression.Invoke(lambdaExpression, invokeArguments); var resultLambda = rule.IsDisablingRule ? Expression.Lambda <Func <object, object[], object> >(Expression.Convert(invokeExpression, typeof(object)), modelParameter, optionsParameter) : Expression.Lambda <Func <object, object[], object> >(invokeExpression, modelParameter, optionsParameter); return(resultLambda.Compile()); }
private static Func <object[], bool> CompileEnablingExpression(DryvCompiledRule rule) { var lambdaExpression = rule.EnablingExpression; EnsurePreevaluationOptionTypes(rule); var optionsParameter = Expression.Parameter(typeof(object[]), "options"); Expression <Func <object[], bool> > resultLambda; if (lambdaExpression != null) { var invokeArguments = new List <Expression>(); AddOptionParameters(invokeArguments, lambdaExpression, optionsParameter); var invokeExpression = Expression.Invoke(lambdaExpression, invokeArguments); resultLambda = Expression.Lambda <Func <object[], bool> >(invokeExpression, optionsParameter); } else { resultLambda = Expression.Lambda <Func <object[], bool> >(Expression.Constant(true), optionsParameter); } return(resultLambda.Compile()); }
private static DryvTranslationException CreateException(string msg, Exception ex, DryvCompiledRule rule) { var sb = new StringBuilder(msg); sb.AppendLine(); sb.Append("The error occurred while translating the following rule for property "); sb.Append(rule.Property.Name); sb.Append(" on type "); sb.Append(rule.ModelType.FullName); sb.AppendLine(":"); sb.Append(rule.ValidationExpression); return(new DryvTranslationException(sb.ToString(), ex)); }
public DryvRuleTreeNode(string path, DryvCompiledRule rule) { this.Path = path ?? throw new ArgumentNullException(nameof(path)); this.Rule = rule ?? throw new ArgumentNullException(nameof(rule)); }
public DryvValidationExecutionException(DryvCompiledRule rule, Exception innerException) : base($"An error occurred while evaluating rule for '{GetPropertyPath(rule)}: {innerException.Message}'", innerException) { }
private static string GetPropertyPath(DryvCompiledRule rule) { return(string.IsNullOrWhiteSpace(rule.ModelPath) ? rule.Property.Name : $"{rule.ModelPath}.{rule.Property.Name}"); }