public override bool Validate(RuleValidation validator) { if (validator == null) { throw new ArgumentNullException("validator"); } bool success = true; if (path == null) { ValidationError error = new ValidationError(Messages.NullUpdate, ErrorNumbers.Error_ParameterNotSet); error.UserData[RuleUserDataKeys.ErrorObject] = this; validator.AddError(error); success = false; } // now make sure that the path is valid string[] parts = path.Split('/'); if (parts[0] == "this") { Type currentType = validator.ThisType; for (int i = 1; i < parts.Length; ++i) { if (parts[i] == "*") { if (i < parts.Length - 1) { // The "*" occurred in the middle of the path, which is a no-no. ValidationError error = new ValidationError(Messages.InvalidWildCardInPathQualifier, ErrorNumbers.Error_InvalidWildCardInPathQualifier); error.UserData[RuleUserDataKeys.ErrorObject] = this; validator.AddError(error); success = false; break; } else { // It occurred at the end, which is okay. break; } } else if (string.IsNullOrEmpty(parts[i]) && i == parts.Length - 1) { // It's okay to end with a "/". break; } while (currentType.IsArray) { currentType = currentType.GetElementType(); } BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy; if (validator.AllowInternalMembers(currentType)) { bindingFlags |= BindingFlags.NonPublic; } FieldInfo field = currentType.GetField(parts[i], bindingFlags); if (field != null) { currentType = field.FieldType; } else { PropertyInfo property = currentType.GetProperty(parts[i], bindingFlags); if (property != null) { currentType = property.PropertyType; } else { string message = string.Format(CultureInfo.CurrentCulture, Messages.UpdateUnknownFieldOrProperty, parts[i]); ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidUpdate); error.UserData[RuleUserDataKeys.ErrorObject] = this; validator.AddError(error); success = false; break; } } } } else { ValidationError error = new ValidationError(Messages.UpdateNotThis, ErrorNumbers.Error_InvalidUpdate); error.UserData[RuleUserDataKeys.ErrorObject] = this; validator.AddError(error); success = false; } return(success); }
internal override bool Validate(RuleValidation validation, MemberInfo member, Type contextType, ParameterInfo[] parameters) { ValidationError error = null; string message = null; if (string.IsNullOrEmpty(attributePath)) { // It is allowed to pass null or the empty string to [RuleRead] or [RuleWrite]. This // is how you indicate that a method or property has no dependencies or side effects. return(true); } bool valid = true; string[] parts = attributePath.Split('/'); // Check the first part. string firstPart = parts[0]; int startOfRelativePortion = 0; if (attributeTarget == RuleAttributeTarget.This) { // When target is "This", the path is allowed to start with the token "this". It is // then skipped for the rest of the validation, and the contextType remains what it // was when passed in. if (firstPart == "this") { ++startOfRelativePortion; } } else { // When target is "Parameter", the path must start with the name of a parameter. bool found = false; for (int p = 0; p < parameters.Length; ++p) { ParameterInfo param = parameters[p]; if (param.Name == firstPart) { found = true; // The context type is the parameter type. contextType = param.ParameterType; break; } } if (!found) { message = string.Format(CultureInfo.CurrentCulture, Messages.InvalidRuleAttributeParameter, firstPart, member.Name); error = new ValidationError(message, ErrorNumbers.Error_InvalidRuleAttributeParameter); error.UserData[RuleUserDataKeys.ErrorObject] = this; validation.AddError(error); return(false); } ++startOfRelativePortion; } int numParts = parts.Length; // Check the last part. The last part is allowed to be empty, or "*". string lastPart = parts[numParts - 1]; if (string.IsNullOrEmpty(lastPart) || lastPart == "*") { numParts -= 1; } // Check the rest of the parts. Type currentType = contextType; for (int i = startOfRelativePortion; i < numParts; ++i) { // Can't have embedded "*" wildcards. if (parts[i] == "*") { // The "*" occurred in the middle of the path, which is a no-no. error = new ValidationError(Messages.InvalidWildCardInPathQualifier, ErrorNumbers.Error_InvalidWildCardInPathQualifier); error.UserData[RuleUserDataKeys.ErrorObject] = this; validation.AddError(error); valid = false; break; } // Skip array types. while (currentType.IsArray) { currentType = currentType.GetElementType(); } // Make sure the member exists in the current type. BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy; if (validation.AllowInternalMembers(currentType)) { bindingFlags |= BindingFlags.NonPublic; } FieldInfo field = currentType.GetField(parts[i], bindingFlags); if (field != null) { currentType = field.FieldType; } else { PropertyInfo property = currentType.GetProperty(parts[i], bindingFlags); if (property != null) { currentType = property.PropertyType; } else { message = string.Format(CultureInfo.CurrentCulture, Messages.UpdateUnknownFieldOrProperty, parts[i]); error = new ValidationError(message, ErrorNumbers.Error_UnknownFieldOrProperty); error.UserData[RuleUserDataKeys.ErrorObject] = this; validation.AddError(error); valid = false; break; } } } return(valid); }