/// <summary> /// Gets the properties of the specified type. /// </summary> private IEnumerable <ViewModelPropertyMap> GetProperties(Type type) { foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(p => p.Name)) { if (property.GetCustomAttribute <JsonIgnoreAttribute>() != null) { continue; } var propertyMap = new ViewModelPropertyMap() { PropertyInfo = property, Name = property.Name, ViewModelProtection = ViewModelProtectionSettings.None, Type = property.PropertyType, TransferAfterPostback = property.GetMethod != null, TransferFirstRequest = property.GetMethod != null, TransferToServer = property.SetMethod != null, JsonConverter = GetJsonConverter(property), Populate = ViewModelJsonConverter.IsComplexType(property.PropertyType) && !ViewModelJsonConverter.IsEnumerable(property.PropertyType) }; var bindAttribute = property.GetCustomAttribute <BindAttribute>(); if (bindAttribute != null) { propertyMap.TransferAfterPostback = bindAttribute.Direction.HasFlag(Direction.ServerToClientPostback); propertyMap.TransferFirstRequest = bindAttribute.Direction.HasFlag(Direction.ServerToClientFirstRequest); propertyMap.TransferToServer = bindAttribute.Direction.HasFlag(Direction.ClientToServerNotInPostbackPath) || bindAttribute.Direction.HasFlag(Direction.ClientToServerInPostbackPath); propertyMap.TransferToServerOnlyInPath = !bindAttribute.Direction.HasFlag(Direction.ClientToServerNotInPostbackPath) && propertyMap.TransferToServer; } var viewModelProtectionAttribute = property.GetCustomAttribute <ViewModelProtectionAttribute>(); if (viewModelProtectionAttribute != null) { propertyMap.ViewModelProtection = viewModelProtectionAttribute.Settings; } var validationAttributes = validationMetadataProvider.GetAttributesForProperty(property); propertyMap.ValidationRules = validationRuleTranslator.TranslateValidationRules(property, validationAttributes).ToList(); yield return(propertyMap); } }
/// <summary> /// Validates the view model. /// </summary> private IEnumerable <ViewModelValidationError> ValidateViewModel(object viewModel, string pathPrefix, HashSet <object> alreadyValidated) { if (alreadyValidated.Contains(viewModel)) { yield break; } if (viewModel == null) { yield break; } var viewModelType = viewModel.GetType(); if (ViewModelJsonConverter.IsPrimitiveType(viewModelType) || ViewModelJsonConverter.IsNullableType(viewModelType)) { yield break; } alreadyValidated.Add(viewModel); if (ViewModelJsonConverter.IsEnumerable(viewModelType)) { // collections var index = 0; foreach (var item in (IEnumerable)viewModel) { foreach (var error in ValidateViewModel(item, pathPrefix + "()[" + index + "]", alreadyValidated)) { yield return(error); } index++; } yield break; } // validate all properties on the object var map = ViewModelJsonConverter.GetSerializationMapForType(viewModel.GetType()); foreach (var property in map.Properties.Where(p => p.TransferToServer)) { var value = property.PropertyInfo.GetValue(viewModel); var path = CombinePath(pathPrefix, property.Name); // validate the property if (property.ValidationRules.Any()) { var context = new ValidationContext(viewModel) { MemberName = property.Name }; foreach (var rule in property.ValidationRules) { var propertyResult = rule.SourceValidationAttribute?.GetValidationResult(value, context); if (propertyResult != ValidationResult.Success) { yield return(new ViewModelValidationError() { PropertyPath = path, ErrorMessage = rule.ErrorMessage }); } } } // inspect objects if (value != null) { if (ViewModelJsonConverter.IsComplexType(property.Type)) { // complex objects foreach (var error in ValidateViewModel(value, path, alreadyValidated)) { yield return(error); } } } } if (viewModel is IValidatableObject) { foreach (var error in ((IValidatableObject)viewModel).Validate(new ValidationContext(viewModel))) { var paths = new List <string>(); if (error.MemberNames != null) { foreach (var memberName in error.MemberNames) { paths.Add(CombinePath(pathPrefix, memberName)); } } if (!paths.Any()) { paths.Add(pathPrefix); } foreach (var memberPath in paths) { yield return(new ViewModelValidationError() { PropertyPath = memberPath, ErrorMessage = error.ErrorMessage }); } } } }