/// <inheritdoc /> public IEnumerable <Frame> GetFrames(Variable operationVariable, List <OperationProperty> properties) { var contextCreator = new ConstructorFrame <ValidationContext>(() => new ValidationContext(null)) { Parameters = { [0] = operationVariable }, }; var hasClassLevel = typeof(IValidatableObject).IsAssignableFrom(operationVariable.VariableType); var hasPropertyLevel = properties.Any(p => p.PropertyInfoVariable.Property.GetAttributes <ValidationAttribute>(true).Any()); if (hasClassLevel || hasPropertyLevel) { yield return(contextCreator); } if (hasClassLevel) { yield return(new ValidatableObjectFrame(contextCreator.Variable, operationVariable)); } if (hasPropertyLevel) { foreach (var p in properties) { var attributes = p.PropertyInfoVariable.Property.GetAttributes <ValidationAttribute>(true); if (attributes.Any()) { yield return(new DataAnnotationsValidatorFrame(contextCreator.Variable, p)); } } } }
/// <summary> /// Adds a ConstructorFrame<T> to the method frames /// </summary> /// <param name="constructor"></param> /// <param name="configure">Optional, any additional configuration for the constructor frame</param> /// <typeparam name="T"></typeparam> /// <returns></returns> /// <exception cref="NotImplementedException"></exception> public FramesCollection CallConstructor <T>(Expression <Func <T> > constructor, Action <ConstructorFrame <T> > configure = null) { var frame = new ConstructorFrame <T>(constructor); configure?.Invoke(frame); Add(frame); return(this); }
private static IEnumerable <Frame> RegisterBlueprintExceptionHandler(Variable exception) { /* * var validationResult = new Blueprint.Api.Middleware.ValidationResult(e.ValidationResults); * return validationResult; */ var validationFailures = new Variable(typeof(ValidationFailures), $"{exception}.{nameof(ValidationException.ValidationResults)}"); var createResult = new ConstructorFrame <ValidationFailedOperationResult>(() => new ValidationFailedOperationResult((ValidationFailures)null)) { Parameters = { [0] = validationFailures }, }; yield return(createResult); yield return(new ReturnFrame(createResult.Variable)); }
/// <inheritdoc /> public void Build(MiddlewareBuilderContext context) { var properties = context.Descriptor.Properties; var operationVariable = context.FindVariable(context.Descriptor.OperationType); var apiOperationDescriptorVariable = context.FindVariable <ApiOperationDescriptor>(); var resultsCreator = new ConstructorFrame <ValidationFailures>(() => new ValidationFailures()); var hasValidationFrames = false; var sources = context.ServiceProvider.GetServices <IValidationSourceBuilder>(); void AddValidatorFrame(Frame frame) { if (!hasValidationFrames) { // Only add the "results creator" frame if there are any actual validation calls. This is the line // that creates an empty ValidationFailures context.ExecuteMethod.Frames.Add(resultsCreator); hasValidationFrames = true; } context.ExecuteMethod.Frames.Add(frame); } var operationProperties = new List <OperationProperty>(); for (var i = 0; i < properties.Length; i++) { var p = properties[i]; var propertyInfoVariable = new PropertyInfoVariable(p, $"{apiOperationDescriptorVariable}.{nameof(ApiOperationDescriptor.Properties)}[{i}]"); var propertyAttributesVariable = new Variable(typeof(object[]), $"{apiOperationDescriptorVariable}.{nameof(ApiOperationDescriptor.PropertyAttributes)}[{i}]"); var propertyValueVariable = operationVariable.GetProperty(p.Name); operationProperties.Add(new OperationProperty { PropertyInfoVariable = propertyInfoVariable, PropertyValueVariable = propertyValueVariable, PropertyAttributesVariable = propertyAttributesVariable, }); } foreach (var s in sources) { foreach (var frame in s.GetFrames(operationVariable, operationProperties)) { AddValidatorFrame(frame); } } // Only bother trying to validate if properties actually exist that are validated if (hasValidationFrames) { /* * var validationFailures = _from above_; * * if (validationFailures.Count > 0) * { * var validationResult = new ValidationResult(validationFailures); * * return validationResult; * } */ var createResult = new ConstructorFrame <ValidationFailedOperationResult>(() => new ValidationFailedOperationResult((ValidationFailures)null)); var failureCount = $"{resultsCreator.Variable}.{nameof(ValidationFailures.Count)}"; context.AppendFrames( new IfBlock($"{failureCount} > 0") { LogFrame.Debug( _validationFailedLogEvent, "Validation failed with {ValidationFailureCount} failures, returning ValidationFailedOperationResult", new Variable <int>(failureCount)), createResult, new ReturnFrame(createResult.Variable), }); } var apiOperationContext = context.FindVariable(typeof(ApiOperationContext)); var activityVariable = apiOperationContext.GetProperty(nameof(ApiOperationContext.Activity)); // Always need to register extra exception handlers because the operation handler itself may do additional validation // and throw an exception to indicate a problem, even if the operation itself is _not_ validated context.RegisterUnhandledExceptionHandler(typeof(ValidationException), e => RegisterBlueprintExceptionHandler(activityVariable, e)); context.RegisterUnhandledExceptionHandler(typeof(System.ComponentModel.DataAnnotations.ValidationException), e => RegisterDataAnnotationsExceptionHandler(activityVariable, e)); }