Esempio n. 1
0
        /// <summary>
        /// Adds an additional target to the condition.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="properties"></param>
        public void AddTarget(object target, params string[] properties)
        {
            // Get the root target instance
            ModelInstance root = ModelInstance.GetModelInstance(target);

            // Set the properties to an empty array if null
            if (properties == null)
            {
                properties = new string[0];
            }

            // Create a single condition target if the specified properties are all on the root
            if (!properties.Any(property => property.Contains('.') || property.Contains('{')))
            {
                targets.Add(new ConditionTarget(this, root, properties));
            }

            // Otherwise, process the property paths to create the necessary sources
            else
            {
                // Process each property path to build up the condition sources
                foreach (string property in properties)
                {
                    AddTarget(root, root.Type.GetPath(property).FirstSteps);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the set of <see cref="Condition"/> instances associated with the specified <see cref="ModelInstance"/>.
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static IEnumerable <Condition> GetConditions(object instance)
        {
            ModelInstance modelInstance = ModelInstance.GetModelInstance(instance);

            if (modelInstance == null)
            {
                throw new ArgumentException("Specified instance is not a valid ModelInstance");
            }

            return(modelInstance.GetExtension <RuleManager>().GetConditions());
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var instance = ModelInstance.GetModelInstance(validationContext.ObjectInstance);
            var source   = new ModelSource(instance.Type, Source);

            // Get the member name by looking up using the display name, since the member name is mysteriously null for MVC3 projects
            var propertyName = validationContext.MemberName ?? validationContext.ObjectType.GetProperties()
                               .Where(p => p.GetCustomAttributes(false).OfType <DisplayAttribute>()
                                      .Any(a => a.Name == validationContext.DisplayName)).Select(p => p.Name).FirstOrDefault();

            var property = instance.Type.Properties[propertyName];

            // Get the list of allowed values
            ModelInstanceList allowedValues = source.GetList(instance);

            if (allowedValues == null)
            {
                return(null);
            }

            // List Property
            if (property.IsList)
            {
                // Get the current property value
                ModelInstanceList items = instance.GetList((ModelReferenceProperty)property);

                // Determine whether the property value is in the list of allowed values
                if (!(items == null || items.All(item => allowedValues.Contains(item))))
                {
                    return(new ValidationResult("Invalid value", new string[] { propertyName }));
                }
            }

            // Reference Property
            else
            {
                // Get the current property value
                ModelInstance item = instance.GetReference((ModelReferenceProperty)property);

                // Determine whether the property value is in the list of allowed values
                if (!(item == null || allowedValues.Contains(item)))
                {
                    return(new ValidationResult("Invalid value", new string[] { propertyName }));
                }
            }

            return(null);
        }
Esempio n. 4
0
            /// <summary>
            /// Sets whether the specified instance is pending deletion.
            /// </summary>
            /// <param name="instance"></param>
            /// <param name="isPendingDelete"></param>
            protected override void SetIsPendingDelete(object instance, bool isPendingDelete)
            {
                // Flag child entities for deletion where the instance is an owner
                ModelInstance modelInstance = ModelInstance.GetModelInstance(instance);

                foreach (var prop in ((EntityModelType)modelInstance.Type).Properties)
                {
                    if (!prop.IsStatic && prop.IsList)
                    {
                        var modelRefProp = (ModelReferenceProperty)prop;
                        if (modelRefProp.PropertyType is EntityModelType)
                        {
                            var entityModelType = (EntityModelType)modelRefProp.PropertyType;
                            if (entityModelType.OwnerProperties.Values.Any(x => x.PropertyType == modelInstance.Type || x.PropertyType.IsSubType(modelInstance.Type)))
                            {
                                foreach (var childInstance in modelRefProp.GetInstances(modelInstance).ToList())
                                {
                                    childInstance.IsPendingDelete = true;
                                }
                            }
                        }
                    }
                }


                // Get the object state from the context
                var state = GetObjectContext().ObjectContext.ObjectStateManager.GetObjectStateEntry(instance);

                // Mark the instance as pending delete
                if (isPendingDelete)
                {
                    state.ChangeState(EntityState.Deleted);
                    ((IModelEntity)instance).IsInitialized = false;
                }

                // Mark the instance as added if the instance is new and is no longer being marked for deletion
                else if (GetId(instance) == null)
                {
                    state.ChangeState(EntityState.Added);
                }

                // Otherwise, mark the instance as modified if the instance is existing and is no longer being marked for deletion
                else
                {
                    state.ChangeState(EntityState.Modified);
                }
            }
Esempio n. 5
0
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ModelInstance instance = ModelInstance.GetModelInstance(validationContext.ObjectInstance);

            // Get the member name by looking up using the display name, since the member name is mysteriously null for MVC3 projects
            var propertyName = validationContext.MemberName ?? validationContext.ObjectType.GetProperties()
                               .Where(p => p.GetCustomAttributes(false).OfType <DisplayAttribute>()
                                      .Any(a => a.Name == validationContext.DisplayName)).Select(p => p.Name).FirstOrDefault();

            ModelProperty sourceProperty = instance.Type.Properties[propertyName];

            if (ComparisonPropertyName == null)
            {
                return(null);
            }

            ModelSource comparePropPath = new ModelSource(instance.Type, ComparisonPropertyName);

            object compareValue = comparePropPath.GetValue(instance);

            int comparison = ((IComparable)compareValue).CompareTo(value);

            switch (Operator)
            {
            case CompareOperator.Equal: return(comparison == 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));

            case CompareOperator.NotEqual: return(comparison != 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));

            case CompareOperator.GreaterThan: return(comparison < 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));

            case CompareOperator.GreaterThanEqual: return(comparison <= 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));

            case CompareOperator.LessThan: return(comparison > 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));

            case CompareOperator.LessThanEqual: return(comparison >= 0 ? null : new ValidationResult("Invalid value", new string[] { propertyName }));
            }

            return(null);
        }
Esempio n. 6
0
        /// <summary>
        /// Creates or removes an condition on the specified target based on the specified condition.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="condition"></param>
        /// <param name="properties"></param>
        public Condition When(string message, object target, Func <bool> condition, params string[] properties)
        {
            // Get the current condition if it exists
            ConditionTarget conditionTarget = ModelInstance.GetModelInstance(target).GetExtension <RuleManager>().GetCondition(this);

            // Add the condition on the target if it does not exist yet
            if (condition())
            {
                // Create a new condition if one does not exist
                if (conditionTarget == null)
                {
                    return(new Condition(this, message, target, properties));
                }

                // Return the existing condition
                else
                {
                    // Update the message if a different message was passed in
                    if (!string.IsNullOrEmpty(message) && message != conditionTarget.Condition.Message)
                    {
                        conditionTarget.Condition.Message = message;
                    }

                    return(conditionTarget.Condition);
                }
            }

            // Destroy the condition if it exists on the target and is no longer valid
            if (conditionTarget != null)
            {
                conditionTarget.Condition.Destroy();
            }

            // Return null to indicate that no condition was created
            return(null);
        }
Esempio n. 7
0
            /// <summary>
            /// Creates a new calculation for the specified property, including an action to set the property
            /// and the expression tree responsible for calculating the expected value.
            /// </summary>
            /// <param name="property"></param>
            /// <param name="action"></param>
            /// <param name="calculation"></param>
            internal Calculation(Expression <Func <TRoot, TProperty> > property, Expression <Func <TRoot, TProperty> > calculation)
                : base(null)
            {
                // Ensure the property argument is a valid expression
                if (property == null || !(property.Body is MemberExpression))
                {
                    throw new ArgumentException("The property expression must be a simple expression that returns a property from the root type (root => root.Property)", "property");
                }

                // Ensure the property member expression is a property, not a field
                var propInfo = (PropertyInfo)((MemberExpression)property.Body).Member as PropertyInfo;

                if (propInfo == null)
                {
                    throw new ArgumentException("Only properties can be calculated via rules, not fields.", "property");
                }

                this.Property    = propInfo.Name;
                this.calculation = calculation;

                // Perform delayed initialization to be able to reference the model type information
                Initialize += (s, e) =>
                {
                    var rootType = RootType;

                    if (rootType == null)
                    {
                        throw new ApplicationException(string.Format("Type '{0}' is not a model type.", typeof(TRoot).FullName));
                    }

                    // Get the model property
                    var prop = rootType.Properties[propInfo.Name];
                    if (prop == null)
                    {
                        throw new ArgumentException("Only valid model properties can be calculated: " + propInfo.Name, "property");
                    }

                    // List property
                    if (prop is ModelReferenceProperty && prop.IsList)
                    {
                        // Compile the calculation outside the action lambda to cache via closure
                        var getListItems = calculation.Compile();

                        this.Action = root =>
                        {
                            // Get the source list
                            var source = ModelInstance.GetModelInstance(root).GetList((ModelReferenceProperty)prop);

                            // Get the set of items the list should contain
                            var items = ((IEnumerable)getListItems(root)).Cast <object>().Select(instance => ModelInstance.GetModelInstance(instance));

                            // Update the list
                            source.Update(items);
                        };
                    }

                    // Reference or value property
                    else
                    {
                        // Ensure the property can be set
                        var setMethod = propInfo.GetSetMethod(true);
                        if (setMethod == null)
                        {
                            throw new ArgumentException("Read-only properties cannot be calculated: " + propInfo.Name, "property");
                        }

                        // Create the expression to set the property using the calculation expression
                        var root   = Expression.Parameter(typeof(TRoot), "root");
                        var setter = Expression.Call(root, setMethod, Expression.Invoke(calculation, root));
                        this.Action = Expression.Lambda <Action <TRoot> >(setter, root).Compile();
                    }

                    // Assert that this rule returns the value of the calculated property
                    Returns(this.Property);

                    // Register for change events as well
                    if (this.path == null)
                    {
                        this.path = ModelContext.Current.GetModelType <TRoot>().GetPath(this.calculation).Path;
                    }
                    if (!String.IsNullOrEmpty(this.path))
                    {
                        OnChangeOf(this.path);
                    }
                };

                // Mark the rule for both server and client execution by default
                RunOnServerAndClient();
            }
Esempio n. 8
0
        /// <summary>
        /// Translates the specified instance of the source type into the destination type.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="createDestinationInstance"></param>
        /// <returns></returns>
        public ModelInstance Translate(ModelInstance source)
        {
            // Create the destination instance
            var destination = createDestinationInstance(source);

            // Apply each property transaction from source to destination
            foreach (var property in Properties)
            {
                // Invoke the source expression for the mapping
                var value = property.SourceExpression == null ? null : property.SourceExpression.Invoke(source);

                // Translate reference properties
                if (property.ReferenceConverter != null)
                {
                    // Translate list properties
                    if (property.DestinationProperty.IsList)
                    {
                        var sourceList = ((IEnumerable)property.SourceExpression.Invoke(source));
                        if (sourceList != null)
                        {
                            var destinationList = property.DestinationSource.GetList(destination);
                            foreach (var instance in property.ReferenceConverter.Translate(sourceList.Cast <object>().Select(i => ModelInstance.GetModelInstance(i))))
                            {
                                destinationList.Add(instance);
                            }
                        }
                    }

                    // Translate instance properties
                    else
                    {
                        var sourceInstance      = ModelInstance.GetModelInstance(property.SourceExpression.Invoke(source));
                        var destinationInstance = property.ReferenceConverter.Translate(sourceInstance);
                        property.DestinationSource.SetValue(destination, destinationInstance.Instance, EnsureDestinationInstance);
                    }
                }

                // Translate value properties
                else
                {
                    if (value != null && property.ValueConverter != null && !((ModelValueProperty)property.DestinationProperty).PropertyType.IsAssignableFrom(value.GetType()))
                    {
                        value = property.ValueConverter.ConvertFrom(null, Thread.CurrentThread.CurrentCulture, value);
                    }
                    else if (value != null && property.DelegateConverter != null)
                    {
                        value = property.DelegateConverter(value);
                    }

                    //the destination property is an enum, see if it is a concrete type
                    //and has a converter associated with it.  This is handled outside
                    //the normal converter paradigm since enums are reference types in ExoModel
                    if (value != null && property.DestinationProperty is IReflectionModelType &&
                        ((IReflectionModelType)property.DestinationProperty).UnderlyingType.BaseType == typeof(Enum))
                    {
                        switch (value.ToString())
                        {
                        //if the enum value is empty just set it to it's default value
                        case "":
                            value = 0;
                            break;

                        default:
                        {
                            var underlyingDestinationType =
                                ((IReflectionModelType)property.DestinationProperty).UnderlyingType;

                            var converter = TypeDescriptor.GetConverter(underlyingDestinationType);
                            value = converter.ConvertFrom(value);
                        }
                        break;
                        }
                    }

                    // Set the value on the destination instance
                    property.DestinationSource.SetValue(destination, value, EnsureDestinationInstance);
                }
            }

            // Return the translated instance
            return(destination);
        }