Example #1
0
        /// <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
                        });
                    }
                }
            }
        }