public ModelValueChangeEvent(ModelInstance instance, ModelValueProperty property, object oldValue, object newValue)
            : base(instance)
        {
            this.Property = property;

            if (property.AutoConvert)
            {
                this.OldValue = oldValue == null ? null : property.Converter.ConvertTo(oldValue, typeof(object));
                this.NewValue = newValue == null ? null : property.Converter.ConvertTo(newValue, typeof(object));
            }
            else
            {
                this.OldValue = oldValue;
                this.NewValue = newValue;
            }
        }
        public ModelValueChangeEvent(ModelInstance instance, ModelValueProperty property, object oldValue, object newValue)
            : base(instance)
        {
            this.Property = property;

            if (property.AutoConvert)
            {
                this.OldValue = oldValue == null ? null : property.Converter.ConvertTo(oldValue, typeof(object));
                this.NewValue = newValue == null ? null : property.Converter.ConvertTo(newValue, typeof(object));
            }
            else
            {
                this.OldValue = oldValue;
                this.NewValue = newValue;
            }
        }
Exemple #3
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) });
        }
Exemple #4
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));
                }));
            }
        }