Ejemplo n.º 1
0
            /// <summary>
            /// Initializes null list properties when updated via a call to <see cref="ModelInstanceList.Add"/> or <see cref="ModelInstanceList.Update"/>.
            /// </summary>
            /// <param name="instance"></param>
            /// <param name="property"></param>
            /// <returns></returns>
            protected override void InitializeList(ModelInstance instance, ModelReferenceProperty property)
            {
                if (property is ReflectionReferenceProperty)
                {
                    // Ensure the property is a writable BusinessObjectList property
                    var propertyInfo = ((ReflectionReferenceProperty)property).PropertyInfo;
                    var listType     = propertyInfo.PropertyType;

                    if (!listType.IsGenericType || listType.GetGenericTypeDefinition() != typeof(ICollection <>))
                    {
                        throw new NotSupportedException("List initialization is only supported for lists of type ICollection<T>.");
                    }

                    if (!propertyInfo.CanWrite)
                    {
                        throw new NotSupportedException("List initialization is only supported for writeable properties.");
                    }

                    var itemType = ((ReflectionModelType)property.PropertyType).UnderlyingType;

                    // Create the list
                    var list = typeof(ObservableCollection <>).MakeGenericType(itemType).GetConstructor(Type.EmptyTypes).Invoke(null);

                    // Assign the list to the property
                    propertyInfo.SetValue(instance.Instance, list, null);
                }
                else
                {
                    throw new NotSupportedException("List initialization is only supported for reflection-based properties.");
                }
            }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the serializable value of a <see cref="ModelProperty"/>.
        /// </summary>
        /// <param name="property"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        internal static object GetPropertyValue(ModelProperty property, IModelPropertySource source)
        {
            ModelReferenceProperty reference = property as ModelReferenceProperty;

            if (reference != null)
            {
                // Serialize lists
                if (reference.IsList)
                {
                    return(source.GetList(reference).Select(item => GetReference(reference, item)));
                }

                // Serialize references
                else
                {
                    return(GetReference(reference, source.GetReference(reference)));
                }
            }

            // Serialize values
            else
            {
                return(source.GetValue((ModelValueProperty)property));
            }
        }
 public ModelReferenceChangeEvent(ModelInstance instance, ModelReferenceProperty property, ModelInstance oldValue, ModelInstance newValue)
     : base(instance)
 {
     this.Property   = property;
     this.OldValue   = oldValue;
     this.OldValueId = (oldValue != null) ? oldValue.Id : null;
     this.NewValue   = newValue;
     this.NewValueId = (newValue != null) ? newValue.Id : null;
 }
Ejemplo n.º 4
0
 public ModelReferenceChangeEvent(ModelInstance instance, ModelReferenceProperty property, ModelInstance oldValue, ModelInstance newValue)
     : base(instance)
 {
     this.Property = property;
     this.OldValue = oldValue;
     this.OldValueId = (oldValue != null) ? oldValue.Id : null;
     this.NewValue = newValue;
     this.NewValueId = (newValue != null) ? newValue.Id : null;
 }
Ejemplo n.º 5
0
            protected override System.Collections.IList ConvertToList(ModelReferenceProperty property, object list)
            {
                // If the list is managed by Entity Framework, convert to a list with listeners
                if (list is RelatedEnd)
                {
                    Type d1          = typeof(CollectionWrapper <>);
                    Type constructed = d1.MakeGenericType(((EntityModelType)property.PropertyType).UnderlyingType);

                    var constructor = constructed.GetConstructors()[0];
                    return((IList)constructor.Invoke(new object[] { list }));
                }

                return(base.ConvertToList(property, list));
            }
Ejemplo n.º 6
0
 /// <summary>
 /// Gets the serializable representation of a <see cref="ModelInstance"/>.
 /// </summary>
 /// <param name="property"></param>
 /// <param name="instance"></param>
 /// <returns></returns>
 internal static object GetReference(ModelReferenceProperty property, ModelInstance instance)
 {
     if (instance == null)
     {
         return(null);
     }
     else if (instance.Type != property.PropertyType)
     {
         return new { id = instance.Id, type = JsonConverter.GetJsonReferenceType(instance.Type) }
     }
     ;
     else
     {
         return(instance.Id);
     }
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Ensure the destination instance path is valid when nulls are encountered along the path.
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="property"></param>
        /// <param name="index"></param>
        bool EnsureDestinationInstance(ModelInstance instance, ModelReferenceProperty property, int index)
        {
            if (property.IsList)
            {
                ModelInstanceList list = instance.GetList(property);
                for (int i = list.Count; i <= index; i++)
                {
                    list.Add(property.PropertyType.Create());
                }
            }
            else
            {
                instance.SetReference(property, property.PropertyType.Create());
            }

            return(true);
        }
Ejemplo n.º 8
0
 protected override System.Collections.IList ConvertToList(ModelReferenceProperty property, object list)
 {
     return (IList)list;
 }
Ejemplo n.º 9
0
        static JsonUtility()
        {
            serializer = new JsonSerializer
            {
                DateParseHandling = DateParseHandling.None,
                Converters        =
                {
                    new UtcDateTimeConverter()
                }
            };
            serializableTypes = new HashSet <Type>();

            // Register converters for types implementing IJsonSerializable or that have DataContract attributes
            // Include all types in ExoWeb and ExoRule automatically
            foreach (var converter in JsonConverter.Infer(
                         typeof(ServiceHandler).Assembly.GetTypes().Union(
                             typeof(Rule).Assembly.GetTypes().Where(type => typeof(Rule).IsAssignableFrom(type)))))
            {
                RegisterConverter(converter);
            }

            // Deserialize Value Change Event
            Func <JsonReader, ModelValueChangeEvent> deserializeValueChangeEvent = (reader) =>
            {
                string             p;
                ModelInstance      instance = null;
                ModelValueProperty property = null;
                object             oldValue = null;
                object             newValue = null;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    case "property":
                        var propertyName = reader.ReadValue <string>();
                        property = (ModelValueProperty)instance.Type.Properties[propertyName];
                        if (property == null)
                        {
                            throw new SerializationException("Unable to deserialize ValueChange: property \"" + propertyName + "\" does not exist for type \"" + instance.Type.Name + "\".");
                        }
                        break;

                    case "oldValue":
                        if (reader.TokenType == JsonToken.StartObject)
                        {
                            oldValue = reader.ReadValue(property.PropertyType);
                        }
                        else
                        {
                            oldValue = property.CoerceValue(reader.Value);
                            reader.Read();
                        }
                        break;

                    case "newValue":
                        if (reader.TokenType == JsonToken.StartObject)
                        {
                            newValue = reader.ReadValue(property.PropertyType);
                        }
                        else
                        {
                            newValue = property.CoerceValue(reader.Value);
                            reader.Read();
                        }
                        break;

                    default:
                        throw new ArgumentException("The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelValueChangeEvent(instance, property, oldValue, newValue));
            };

            // Deserialize Reference Change Event
            Func <JsonReader, ModelReferenceChangeEvent> deserializeReferenceChangeEvent = (reader) =>
            {
                string                 p;
                ModelInstance          instance = null;
                ModelReferenceProperty property = null;
                ModelInstance          oldValue = null;
                ModelInstance          newValue = null;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    case "property":
                        var propertyName = reader.ReadValue <string>();
                        property = (ModelReferenceProperty)instance.Type.Properties[propertyName];
                        if (property == null)
                        {
                            throw new SerializationException("Unable to deserialize ReferenceChange: property \"" + propertyName + "\" does not exist for type \"" + instance.Type.Name + "\".");
                        }
                        break;

                    case "oldValue":
                        oldValue = reader.ReadValue <ModelInstance>();
                        break;

                    case "newValue":
                        newValue = reader.ReadValue <ModelInstance>();
                        break;

                    default:
                        throw new ArgumentException(@"The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelReferenceChangeEvent(instance, property, oldValue, newValue));
            };

            // Deserialize List Change Event
            Func <JsonReader, ModelListChangeEvent> deserializeListChangeEvent = (reader) =>
            {
                string                 p;
                ModelInstance          instance = null;
                ModelReferenceProperty property = null;
                ModelInstance[]        added    = null;
                ModelInstance[]        removed  = null;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    case "property":
                        var propertyName = reader.ReadValue <string>();
                        property = (ModelReferenceProperty)instance.Type.Properties[propertyName];
                        if (property == null)
                        {
                            throw new SerializationException("Unable to deserialize ListChange: property \"" + propertyName + "\" does not exist for type \"" + instance.Type.Name + "\".");
                        }
                        break;

                    case "added":
                        added = reader.ReadValue <ModelInstance[]>();
                        break;

                    case "removed":
                        removed = reader.ReadValue <ModelInstance[]>();
                        break;

                    default:
                        throw new ArgumentException(@"The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelListChangeEvent(instance, property, added, removed));
            };

            // Deserialize Init New Event
            Func <JsonReader, ModelInitEvent.InitNew> deserializeInitNewEvent = (reader) =>
            {
                string        p;
                ModelInstance instance = null;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    default:
                        throw new ArgumentException(@"The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelInitEvent.InitNew(instance));
            };

            // Deserialize Init Existing Event
            Func <JsonReader, ModelInitEvent.InitExisting> deserializeInitExistingEvent = (reader) =>
            {
                string        p;
                ModelInstance instance = null;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    default:
                        throw new ArgumentException(@"The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelInitEvent.InitExisting(instance));
            };

            // Deserialize Delete Event
            Func <JsonReader, ModelDeleteEvent> deserializeDeleteEvent = (reader) =>
            {
                string        p;
                ModelInstance instance        = null;
                bool          isPendingDelete = false;
                while (reader.ReadProperty(out p))
                {
                    switch (p)
                    {
                    case "instance":
                        instance = reader.ReadValue <ModelInstance>();
                        break;

                    case "isPendingDelete":
                        isPendingDelete = reader.ReadValue <bool>();
                        break;

                    default:
                        throw new ArgumentException(@"The specified property could not be deserialized.", p);
                    }
                }
                return(new ModelDeleteEvent(instance, isPendingDelete));
            };

            // Construct Model Instance
            var createModelInstance = typeof(ModelInstance).GetConstructor(
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new Type[] { typeof(ModelType), typeof(string) },
                null);

            // Register custom converters for ModelType, ModelProperty, ModelMethod, ModelInstance, ModelEvent
            foreach (var converter in
                     new JsonConverter[]
            {
                // Model Type
                new JsonConverter <ModelType>(
                    (modelType, json) =>
                {
                    // Base Type
                    if (modelType.BaseType != null)
                    {
                        json.Set("baseType", JsonConverter.GetJsonReferenceType(modelType.BaseType));
                    }

                    // Base Type
                    if (!String.IsNullOrEmpty(modelType.Format))
                    {
                        json.Set("format", modelType.Format);
                    }

                    // Properties
                    if (modelType.Properties.Any())
                    {
                        json.Set("properties", modelType.Properties
                                 .Where(property => property.DeclaringType == modelType && ExoWeb.IncludeInClientModel(property))
                                 .ToDictionary(property => property.Name));
                    }

                    // Methods
                    if (modelType.Methods.Any())
                    {
                        json.Set("methods", modelType.Methods.ToDictionary(method => method.Name));
                    }

                    // Rules
                    var rules = Rule.GetRegisteredRules(modelType).ToList();
                    var typeRules = rules.Where(rule => (rule.ExecutionLocation & RuleExecutionLocation.Client) > 0 && !(rule is IPropertyRule)).ToArray();
                    if (typeRules.Any())
                    {
                        json.Set("rules", typeRules);
                    }

                    // Condition Types
                    var serverConditionTypes = rules
                                               .Where(rule => (rule.ExecutionLocation & RuleExecutionLocation.Client) == 0)
                                               .SelectMany(rule => rule.ConditionTypes)
                                               .ToArray();
                    if (serverConditionTypes.Any())
                    {
                        json.Set("conditionTypes", serverConditionTypes);
                    }

                    // Exports
                    var exports = json.Global <Dictionary <string, string> >("exports");
                    if (exports.Any())
                    {
                        json.Set("exports", json.Global <Dictionary <string, string> >("exports"));
                    }
                },
                    json => { throw new NotSupportedException("ModelType cannot be deserialized."); }),

                // Model Property
                new JsonConverter <ModelProperty>(
                    (property, json) =>
                {
                    // Type
                    string type = (property is ModelValueProperty ?
                                   JsonConverter.GetJsonValueType(((ModelValueProperty)property).PropertyType) ?? "Object" :
                                   JsonConverter.GetJsonReferenceType(((ModelReferenceProperty)property).PropertyType)) +
                                  (property.IsList ? "[]" : "");
                    json.Set("type", type);

                    // IsStatic
                    if (property.IsStatic)
                    {
                        json.Set("isStatic", true);
                    }

                    // IsPersisted
                    if (!property.IsPersisted && !property.IsStatic)
                    {
                        json.Set("isPersisted", false);
                    }

                    // IsCalculated
                    if (property.IsCalculated)
                    {
                        json.Set("isCalculated", true);
                    }

                    // Index
                    int index = 0;
                    foreach (ModelProperty p in property.DeclaringType.Properties)
                    {
                        if (p == property)
                        {
                            break;
                        }
                        if (ExoWeb.IncludeInClientModel(p) && !p.IsStatic)
                        {
                            index++;
                        }
                    }
                    if (!property.IsStatic)
                    {
                        json.Set("index", index);
                    }

                    // Format
                    string format = property.Format;
                    if (!string.IsNullOrEmpty(format))
                    {
                        json.Set("format", format);
                    }

                    // Label
                    string label = property.Label;
                    if (!string.IsNullOrEmpty(label))
                    {
                        json.Set("label", label);
                    }

                    // Help Text
                    string helptext = property.HelpText;
                    if (!string.IsNullOrEmpty(helptext))
                    {
                        json.Set("helptext", helptext);
                    }

                    // Rules
                    var rules = Rule
                                .GetRegisteredRules(property.DeclaringType)
                                .Where(rule => (rule.ExecutionLocation & RuleExecutionLocation.Client) > 0 && rule is IPropertyRule && rule.RootType.Properties[((IPropertyRule)rule).Property] == property)
                                .ToDictionary(rule =>
                                              rule is ICalculationRule ? "calculated" :
                                              String.Format("{0}.{1}.{2}", rule.RootType.Name, ((IPropertyRule)rule).Property, ((IPropertyRule)rule).Name) == rule.Name ?
                                              ((IPropertyRule)rule).Name.Substring(0, 1).ToLower() + ((IPropertyRule)rule).Name.Substring(1) :
                                              rule.Name);
                    if (rules.Any())
                    {
                        json.Set("rules", rules);
                    }

                    // Default Value
                    if (property is ModelValueProperty)
                    {
                        var defaultValue = ((ModelValueProperty)property).DefaultValue;
                        if (defaultValue != null)
                        {
                            json.Set("defaultValue", ((ModelValueProperty)property).DefaultValue);
                        }
                    }
                },
                    json => { throw new NotSupportedException("ModelProperty cannot be deserialized."); }),

                // Model Method
                new JsonConverter <ModelMethod>(
                    (method, json) =>
                {
                    // Parameters
                    json.Set("parameters", method.Parameters.Select(p => p.Name));

                    // IsStatic
                    json.Set("isStatic", method.IsStatic);
                },
                    json => { throw new NotSupportedException("ModelMethod cannot be deserialized."); }),

                // Model Instance
                new JsonConverter <ModelInstance>(
                    (instance, json) =>
                {
                    json.Set("id", instance.Id);
                    json.Set("type", instance.Type.Name);
                },
                    reader =>
                {
                    string p;
                    ModelType type = null;
                    string id = null;
                    while (reader.ReadProperty(out p))
                    {
                        switch (p)
                        {
                        case "type":
                            type = ModelContext.Current.GetModelType(reader.ReadValue <string>());
                            break;

                        case "id":
                            id = reader.ReadValue <string>();
                            break;

                        // Ignore
                        case "isNew":
                            reader.ReadValue <bool>();
                            break;

                        default:
                            throw new ArgumentException(@"The specified property could not be deserialized.", p);
                        }
                    }
                    return((ModelInstance)createModelInstance.Invoke(new object[] { type, id }));
                }),

                // Model Event
                new JsonConverter <ModelEvent>(
                    (modelEvent, json) => { throw new NotSupportedException("ModelEvent cannot be deserialized."); },
                    (reader) =>
                {
                    string p;
                    if (reader.ReadProperty(out p) && p == "type")
                    {
                        string eventName = reader.ReadValue <string>();
                        switch (eventName)
                        {
                        case "ValueChange": return(deserializeValueChangeEvent(reader));

                        case "ReferenceChange": return(deserializeReferenceChangeEvent(reader));

                        case "ListChange": return(deserializeListChangeEvent(reader));

                        case "InitNew": return(deserializeInitNewEvent(reader));

                        case "InitExisting": return(deserializeInitExistingEvent(reader));

                        case "Delete": return(deserializeDeleteEvent(reader));
                        }
                        throw new NotSupportedException(eventName + " event cannot be deserialized.");
                    }
                    else
                    {
                        throw new FormatException("The type parameter 'type' must be the first serialized value in model event json.");
                    }
                }),

                // Model Value Change Event
                new JsonConverter <ModelValueChangeEvent>(
                    (modelEvent, json) =>
                {
                    //Property sequence matters
                    json.Set("type", "ValueChange");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                    json.Set("property", modelEvent.Property.Name);
                    json.Set("oldValue", modelEvent.OldValue);
                    json.Set("newValue", modelEvent.NewValue);
                },
                    deserializeValueChangeEvent),

                // Model Reference Change Event
                new JsonConverter <ModelReferenceChangeEvent>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "ReferenceChange");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                    json.Set("property", modelEvent.Property.Name);
                    json.Set("oldValue", GetEventInstance(modelEvent.OldValue, modelEvent.OldValueId));
                    json.Set("newValue", GetEventInstance(modelEvent.NewValue, modelEvent.NewValueId));
                },
                    deserializeReferenceChangeEvent),

                // Model List Change Event
                new JsonConverter <ModelListChangeEvent>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "ListChange");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                    json.Set("property", modelEvent.Property.Name);
                    json.Set("added", modelEvent.Added.Select((instance, index) => GetEventInstance(instance, modelEvent.AddedIds.ElementAt(index))));
                    json.Set("removed", modelEvent.Removed.Select((instance, index) => GetEventInstance(instance, modelEvent.RemovedIds.ElementAt(index))));
                },
                    deserializeListChangeEvent),

                // Model Init New Event
                new JsonConverter <ModelInitEvent.InitNew>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "InitNew");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                },
                    deserializeInitNewEvent),

                // Model Init Existing Event
                new JsonConverter <ModelInitEvent.InitExisting>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "InitExisting");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                },
                    deserializeInitExistingEvent),

                // Model Delete Event
                new JsonConverter <ModelDeleteEvent>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "Delete");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                    json.Set("isPendingDelete", modelEvent.IsPendingDelete);
                },
                    deserializeDeleteEvent),

                // Model Save Event
                new JsonConverter <ModelSaveEvent>(
                    (modelEvent, json) =>
                {
                    json.Set("type", "Save");
                    json.Set("instance", GetEventInstance(modelEvent.Instance, modelEvent.InstanceId));
                    json.Set("added", modelEvent.Added.Select(instance => new Dictionary <string, string>()
                    {
                        { "type", instance.Type.Name }, { "oldId", instance.OriginalId }, { "newId", instance.Id }
                    }));
                    json.Set("modified", modelEvent.Modified);
                    json.Set("deleted", modelEvent.Deleted);
                },
                    json => { throw new NotSupportedException("ModelSaveEvent cannot be deserialized."); }),

                // Condition Type
                new JsonConverter <ConditionType>(
                    (conditionType, json) =>
                {
                    json.Set("code", conditionType.Code);
                    json.Set("category", conditionType.Category.ToString());

                    if (conditionType.Sets != null && conditionType.Sets.Any())
                    {
                        json.Set("sets", conditionType.Sets.Select(set => set.Name));
                    }

                    json.Set("message", conditionType.Message);
                },
                    json => { throw new NotSupportedException("ConditionType cannot be deserialized."); }),

                // Condition
                new JsonConverter <Condition>(
                    (condition, json) =>
                {
                    if (condition.Message != condition.Type.Message)
                    {
                        json.Set("message", condition.Message);
                    }
                    json.Set("targets", condition.Targets.Where(ct => ct.Target != null));
                },
                    json => { throw new NotSupportedException("Condition cannot be deserialized."); }),

                // Condition Target
                new JsonConverter <ConditionTarget>(
                    (conditionTarget, json) =>
                {
                    json.Set("instance", conditionTarget.Target);
                    json.Set("properties", conditionTarget.Properties);
                },
                    json => { throw new NotSupportedException("ConditionTarget cannot be deserialized."); }),

                // Rule
                new JsonConverter <Rule>(
                    (rule, json) =>
                {
                    if (rule is ICalculationRule)
                    {
                        var calculation = (ICalculationRule)rule;
                        json.Set("onChangeOf", calculation.Predicates);
                        if (rule is IClientCalculationRule)
                        {
                            var clientCalc = (IClientCalculationRule)rule;
                            json.Set("calculate", clientCalc.FunctionBody);
                            foreach (var export in clientCalc.Exports)
                            {
                                json.Global <Dictionary <string, string> >("exports")[export.Key] = export.Value;
                            }
                        }
                        else
                        {
                            json.Set("calculate", calculation.Calculation);
                        }
                    }

                    else if (rule is IConditionRule)
                    {
                        var condition = (IConditionRule)rule;
                        json.Set("type", "condition");
                        json.Set("properties", condition.Properties);
                        json.Set("onChangeOf", condition.Predicates);
                        json.Set("conditionType", condition.ConditionType);
                        json.Set("assert", condition.Condition);
                    }

                    else
                    {
                        throw new NotSupportedException("Rules of type " + rule.GetType().FullName + " cannot be serialized.  Call ExoWeb.RegisterConverters() to register a converter to support serializing rules of this type.");
                    }
                },
                    json => { throw new NotSupportedException("Rule cannot be deserialized."); }),

                // AllowedValuesRule
                new JsonConverter <AllowedValuesRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    var sourceExpression = rule.SourceExpression;
                    if (sourceExpression != null)
                    {
                        json.Set("fn", sourceExpression.Expression);
                        if (!String.IsNullOrEmpty(rule.Path))
                        {
                            json.Set("onChangeOf", new string[] { rule.Path });
                        }
                    }
                    else
                    {
                        json.Set("source", rule.Source);
                    }
                    if (rule.IgnoreValidation)
                    {
                        json.Set("ignoreValidation", rule.IgnoreValidation);
                    }
                },
                    json => { throw new NotSupportedException("AllowedValuesRule cannot be deserialized."); }),

                // CompareRule
                new JsonConverter <CompareRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    json.Set("compareOperator", rule.CompareOperator.ToString());
                    json.Set("compareSource", rule.CompareSource);
                },
                    json => { throw new NotSupportedException("CompareRule cannot be deserialized."); }),

                // ListLengthRule
                new JsonConverter <ListLengthRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);

                    // Min
                    if (rule.MinExpression != null)
                    {
                        json.Set("minFn", rule.MinExpression.Expression);
                    }
                    else
                    {
                        json.Set("min", rule.Minimum);
                    }

                    // Max
                    if (rule.MaxExpression != null)
                    {
                        json.Set("maxFn", rule.MaxExpression.Expression);
                    }
                    else
                    {
                        json.Set("max", rule.Maximum);
                    }

                    // OnChangeOf
                    if (!String.IsNullOrEmpty(rule.Path))
                    {
                        json.Set("onChangeOf", new string[] { rule.Path });
                    }
                },
                    json => { throw new NotSupportedException("ListLengthRule cannot be deserialized."); }),

                // RangeRule
                new JsonConverter <RangeRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);

                    // Min
                    if (rule.MinExpression != null)
                    {
                        json.Set("minFn", rule.MinExpression.Expression);
                    }
                    else
                    {
                        json.Set("min", rule.Minimum);
                    }

                    // Max
                    if (rule.MaxExpression != null)
                    {
                        json.Set("maxFn", rule.MaxExpression.Expression);
                    }
                    else
                    {
                        json.Set("max", rule.Maximum);
                    }

                    // OnChangeOf
                    if (!String.IsNullOrEmpty(rule.Path))
                    {
                        json.Set("onChangeOf", new string[] { rule.Path });
                    }
                },
                    json => { throw new NotSupportedException("RangeRule cannot be deserialized."); }),

                // ValidationRule
                new JsonConverter <ValidationRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);

                    // Validation
                    json.Set("isError", rule.ValidationExpression.Expression);

                    // ErrorMessage
                    if (rule.ErrorMessageResource != null)
                    {
                        json.Set("message", rule.ErrorMessageResource);
                    }
                    else
                    {
                        json.Set("message", rule.ErrorMessageExpression.Expression);
                    }

                    json.Set("properties", rule.AdditionalTargets);

                    // OnChangeOf
                    if (!String.IsNullOrEmpty(rule.Path))
                    {
                        json.Set("onChangeOf", new string[] { rule.Path });
                    }
                },
                    json => { throw new NotSupportedException("ValidationRule cannot be deserialized."); }),

                // RequiredRule
                new JsonConverter <RequiredRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    if (rule.RequiredValue != null)
                    {
                        json.Set("requiredValue", rule.RequiredValue);
                    }
                },
                    json => { throw new NotSupportedException("RequiredRule cannot be deserialized."); }),

                // RequiredIfRule
                new JsonConverter <RequiredIfRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    if (rule.RequiredExpression != null)
                    {
                        json.Set("fn", rule.RequiredExpression.Expression);

                        // OnChangeOf
                        if (!String.IsNullOrEmpty(rule.Path))
                        {
                            json.Set("onChangeOf", new string[] { rule.Path });
                        }
                    }
                    else
                    {
                        json.Set("compareOperator", rule.CompareOperator.ToString());
                        json.Set("compareSource", rule.CompareSource);
                        json.Set("compareValue", rule.CompareValue);
                    }

                    if (rule.RequiredValue != null)
                    {
                        json.Set("requiredValue", rule.RequiredValue);
                    }
                },
                    json => { throw new NotSupportedException("RequiredIfRule cannot be deserialized."); }),

                // OwnerRule
                new JsonConverter <OwnerRule>(
                    (rule, json) => SerializePropertyRule(rule, json),
                    json => { throw new NotSupportedException("OwnerRule cannot be deserialized."); }),

                // StringLengthRule
                new JsonConverter <StringLengthRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    if (rule.Minimum > 0)
                    {
                        json.Set("min", rule.Minimum);
                    }
                    if (rule.Maximum > 0)
                    {
                        json.Set("max", rule.Maximum);
                    }
                },
                    json => { throw new NotSupportedException("StringLengthRule cannot be deserialized."); }),

                // StringFormatRule
                new JsonConverter <StringFormatRule>(
                    (rule, json) =>
                {
                    SerializePropertyRule(rule, json);
                    if (!String.IsNullOrEmpty(rule.FormatDescription))
                    {
                        json.Set("description", rule.FormatDescription);
                    }
                    json.Set("expression", rule.FormatExpression.ToString());
                    if (!String.IsNullOrEmpty(rule.ReformatExpression))
                    {
                        json.Set("reformat", rule.ReformatExpression);
                    }
                },
                    json => { throw new NotSupportedException("StringFormatRule cannot be deserialized."); }),
            })
            {
                JsonUtility.RegisterConverter(converter);
            }

            // Cache the method info of the deserialize method
            // The non-generic version of this method was added in .NET 4.0
            deserialize = serializer.GetType().GetMethod("Deserialize", new Type[] { typeof(string) });
        }
Ejemplo n.º 10
0
 protected override System.Collections.IList ConvertToList(ModelReferenceProperty property, object list)
 {
     return((IList)list);
 }
Ejemplo n.º 11
0
        protected override object GetMissingPropertyValue(string jsPropertyName)
        {
            // special meta property
            if (jsPropertyName == "meta")
            {
                return(LazyDefineProperty("meta", new Meta(Engine, RealObject)));
            }

            // handle model properties
            string modelPropertyName;

            if (jsPropertyName.StartsWith(GetterPrefix))
            {
                modelPropertyName = jsPropertyName.Substring(GetterPrefix.Length);
            }
            else if (jsPropertyName.StartsWith(SetterPrefix))
            {
                throw new InvalidOperationException("Properties are read-only");
            }
            else
            {
                throw new InvalidOperationException("Only property get accessors are supported on model objects: " + jsPropertyName);
            }

            ModelProperty property = RealObject.Type.Properties[modelPropertyName];

            if (property == null)
            {
                throw new InvalidPropertyException(RealObject.Type, modelPropertyName);
            }

            if (property is ModelValueProperty)
            {
                // optimization: cast outside of delegate
                ModelValueProperty valueProperty = (ModelValueProperty)property;

                return(LazyDefineMethod(jsPropertyName, instance =>
                {
                    var value = instance.GetValue(valueProperty);

                    if (value is decimal)
                    {
                        return decimal.ToDouble((decimal)value);
                    }

                    if (value is float)
                    {
                        return Convert.ToDouble((float)value);
                    }

                    if (value is long)
                    {
                        return Convert.ToInt32((long)value);
                    }

                    if (value is DateTime)
                    {
                        var dateTime = (DateTime)value;

                        // Use the same serialization format as `JsonUtility.UtcDateTimeConverter`.
                        var dateString = dateTime.ToUniversalTime().ToString(@"yyyy-MM-dd\THH:mm:ss.fff\Z");

                        var jsDate = Engine.Date.Construct(dateString);

                        return jsDate;
                    }

                    return value;
                }));
            }

            ModelReferenceProperty refProperty = (ModelReferenceProperty)property;

            if (refProperty.IsList)
            {
                return(LazyDefineMethod(jsPropertyName, instance =>
                {
                    return factory.Wrap(instance.GetList(refProperty));
                }));
            }
            else
            {
                return(LazyDefineMethod(jsPropertyName, instance =>
                {
                    return factory.Wrap(instance.GetReference(refProperty));
                }));
            }
        }
Ejemplo n.º 12
0
            /// <summary>
            /// Processes static property paths in order to determine the information to serialize.
            /// </summary>
            /// <param name="path"></param>
            internal static void PrepareStaticPath(string path, ServiceResponse response)
            {
                string type     = null;
                string property = null;

                try
                {
                    if (path.IndexOf('.') < 0)
                    {
                        throw new ArgumentException("'" + path + "' is not a valid static property path.");
                    }

                    // Split the static property reference
                    int propertyIndex = path.LastIndexOf('.');
                    type     = path.Substring(0, propertyIndex);
                    property = path.Substring(propertyIndex + 1);

                    // Get the model type
                    ModelType modelType = ModelContext.Current.GetModelType(type);
                    if (modelType == null)
                    {
                        throw new ArgumentException("'" + type + "' is not a valid model type for the static property path of '" + path + "'.");
                    }

                    // Get the model property
                    ModelProperty modelProperty = modelType.Properties[property];
                    if (modelProperty == null || !modelProperty.IsStatic)
                    {
                        throw new ArgumentException("'" + property + "' is not a valid property for the static property path of '" + path + "'.");
                    }

                    // Add the property to the set of static properties to serialize
                    response.GetModelTypeInfo(modelType).StaticProperties.Add(modelProperty);

                    // Register instances for static reference properties to be serialized
                    ModelReferenceProperty reference = modelProperty as ModelReferenceProperty;
                    if (reference != null)
                    {
                        // Get the cached set of instances to be serialized for the property type
                        ModelTypeInfo propertyTypeInfo = response.GetModelTypeInfo(reference.PropertyType);

                        // Static lists
                        if (reference.IsList)
                        {
                            foreach (ModelInstance instance in modelType.GetList(reference))
                            {
                                ModelTypeInfo typeInfo = instance.Type == reference.PropertyType ? propertyTypeInfo : response.GetModelTypeInfo(instance.Type);
                                if (!typeInfo.Instances.ContainsKey(instance.Id))
                                {
                                    typeInfo.Instances.Add(instance.Id, new ModelInstanceInfo(instance));
                                }
                            }
                        }

                        // Static references
                        else
                        {
                            ModelInstance instance = modelType.GetReference(reference);

                            if (instance != null)
                            {
                                ModelTypeInfo typeInfo = instance.Type == reference.PropertyType ? propertyTypeInfo : response.GetModelTypeInfo(instance.Type);
                                if (!typeInfo.Instances.ContainsKey(instance.Id))
                                {
                                    typeInfo.Instances.Add(instance.Id, new ModelInstanceInfo(instance));
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(string.Format("Error preparing static path '{0}'{1}{2}: [{3}]",
                                                                 path,
                                                                 type == null ? string.Empty : (" for type '" + type + "'"),
                                                                 property == null ? string.Empty : (" and property '" + property + "'"),
                                                                 ex.Message),
                                                   ex);
                }
            }
Ejemplo n.º 13
0
        /// <summary>
        /// Gets the set of precondition rules created by the provider.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public virtual IEnumerable <Rule> GetRules(Type sourceType, string name)
        {
            if (rules == null)
            {
                // Process each type
                var context = ModelContext.Current;
                rules = new List <Rule>();
                foreach (var type in types.Select(t => context.GetModelType(t)).Where(t => t != null))
                {
                    // Process each instance property declared on the current type
                    foreach (var property in type.Properties.Where(property => property.DeclaringType == type && !property.IsStatic))
                    {
                        // Required Attribute
                        foreach (var attr in property.GetAttributes <RequiredAttribute>().Take(1))
                        {
                            object requiredValue = null;
                            if (property is ModelValueProperty && ((ModelValueProperty)property).PropertyType == typeof(bool))
                            {
                                requiredValue = true;
                            }

                            // Use the error message if one is specifed, otherwise use the default bahavior
                            if (string.IsNullOrEmpty(attr.ErrorMessage))
                            {
                                rules.Add(new RequiredRule(type.Name, property.Name, requiredValue));
                            }
                            else
                            {
                                rules.Add(new RequiredRule(type.Name, property.Name, attr.ErrorMessage, requiredValue));
                            }
                        }

                        // String Length Attribute
                        foreach (var attr in property.GetAttributes <StringLengthAttribute>().Take(1))
                        {
                            // Use the error message if one is specifed, otherwise use the default bahavior
                            if (string.IsNullOrEmpty(attr.ErrorMessage))
                            {
                                rules.Add(new StringLengthRule(type.Name, property.Name, attr.MinimumLength, attr.MaximumLength));
                            }
                            else
                            {
                                rules.Add(new StringLengthRule(type.Name, property.Name, attr.MinimumLength, attr.MaximumLength, attr.ErrorMessage));
                            }
                        }

                        // Range Attribute
                        foreach (var attr in property.GetAttributes <RangeAttribute>().Take(1))
                        {
                            // Use the error message if one is specifed, otherwise use the default bahavior
                            if (string.IsNullOrEmpty(attr.ErrorMessage))
                            {
                                rules.Add(new RangeRule(type.Name, property.Name, (IComparable)attr.Minimum, (IComparable)attr.Maximum));
                            }
                            else
                            {
                                rules.Add(new RangeRule(type.Name, property.Name, (IComparable)attr.Minimum, (IComparable)attr.Maximum, attr.ErrorMessage));
                            }
                        }

                        //Compare Attribute
                        foreach (var attr in property.GetAttributes <CompareAttribute>().Take(1))
                        {
                            // Use the error message if one is specifed, otherwise use the default bahavior
                            if (string.IsNullOrEmpty(attr.ErrorMessage))
                            {
                                rules.Add(new CompareRule(type.Name, property.Name, attr.ComparisonPropertyName, attr.Operator));
                            }
                            else
                            {
                                rules.Add(new CompareRule(type.Name, property.Name, attr.ComparisonPropertyName, attr.Operator, attr.ErrorMessage));
                            }
                        }

                        //// ListLength Attribute
                        //foreach (var attr in property.GetAttributes<ListLengthAttribute>().Take(1))
                        //{
                        //	// Use the error message if one is specifed, otherwise use the default bahavior
                        //	if (string.IsNullOrEmpty(attr.ErrorMessage))
                        //		rules.Add(new ListLengthRule(type.Name, property.Name, attr.StaticLength, attr.LengthCompareProperty, attr.CompareOp));
                        //	else
                        //		rules.Add(new ListLengthRule(type.Name, property.Name, attr.StaticLength, attr.LengthCompareProperty, attr.CompareOp, attr.ErrorMessage));
                        //}

                        // Regular Expression Attribute
                        foreach (var attr in property.GetAttributes <RegularExpressionAttribute>().Take(1))
                        {
                            rules.Add(CreateFormatRule(type.Name, property.Name, attr));
                        }

                        // Allowed Values Attribute
                        ModelReferenceProperty reference = property as ModelReferenceProperty;
                        if (reference != null)
                        {
                            string errorMessage = null;
                            foreach (var attr in property.GetAttributes <AllowedValuesAttribute>().Take(1))
                            {
                                errorMessage = attr.ErrorMessage;
                            }

                            foreach (var source in property.GetAttributes <AllowedValuesAttribute>()
                                     .Select(attr => attr.Source)
                                     .Union(reference.PropertyType.GetAttributes <AllowedValuesAttribute>()
                                            .Select(attr => attr.Source.Contains('.') ? attr.Source : reference.PropertyType.Name + '.' + attr.Source)
                                            .Take(1)))
                            {
                                rules.Add(string.IsNullOrEmpty(errorMessage) ? new AllowedValuesRule(type.Name, property.Name, source) : new AllowedValuesRule(type.Name, property.Name, source, errorMessage));
                            }
                        }
                    }
                }
            }
            return(rules);
        }
Ejemplo n.º 14
0
            /// <summary>
            /// Initializes null list properties when updated via a call to <see cref="ModelInstanceList.Add"/> or <see cref="ModelInstanceList.Update"/>.
            /// </summary>
            /// <param name="instance"></param>
            /// <param name="property"></param>
            /// <returns></returns>
            protected override void InitializeList(ModelInstance instance, ModelReferenceProperty property)
            {
                if (property is ReflectionReferenceProperty)
                {
                    // Ensure the property is a writable BusinessObjectList property
                    var propertyInfo = ((ReflectionReferenceProperty)property).PropertyInfo;
                    var listType = propertyInfo.PropertyType;

                    if(!listType.IsGenericType || listType.GetGenericTypeDefinition() != typeof(ICollection<>))
                        throw new NotSupportedException("List initialization is only supported for lists of type ICollection<T>.");

                    if (!propertyInfo.CanWrite)
                        throw new NotSupportedException("List initialization is only supported for writeable properties.");

                    var itemType = ((ReflectionModelType)property.PropertyType).UnderlyingType;

                    // Create the list
                    var list = typeof(ObservableCollection<>).MakeGenericType(itemType).GetConstructor(Type.EmptyTypes).Invoke(null);

                    // Assign the list to the property
                    propertyInfo.SetValue(instance.Instance, list, null);
                }
                else
                    throw new NotSupportedException("List initialization is only supported for reflection-based properties.");
            }
Ejemplo n.º 15
0
            protected override System.Collections.IList ConvertToList(ModelReferenceProperty property, object list)
            {
                // If the list is managed by Entity Framework, convert to a list with listeners
                if (list is RelatedEnd)
                {
                    Type d1 = typeof(CollectionWrapper<>);
                    Type constructed = d1.MakeGenericType(((EntityModelType) property.PropertyType).UnderlyingType);

                    var constructor = constructed.GetConstructors()[0];
                    return (IList) constructor.Invoke(new object[] { list });
                }

                return base.ConvertToList(property, list);
            }