Example #1
0
        /// <summary>
        /// Deserialize a JSON value into an instance.
        /// </summary>
        /// <param name="value">The JSON value.</param>
        /// <param name="instance">The instance to deserialize into.</param>
        /// <param name="ignoreCustomSerialization">
        /// A value to indicate whether or not custom serialization should be
        /// ignored if the instance implements
        /// ICustomMobileServiceTableSerialization.  This flag is used by
        /// implementations of ICustomMobileServiceTableSerialization that want
        /// to invoke the default serialization behavior.
        /// </param>
        public static void Deserialize(JToken value, object instance, bool ignoreCustomSerialization)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            else if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // If the instance implements
            // ICustomMobileServiceTableSerialization, allow it to handle its
            // own deserialization.
            if (!ignoreCustomSerialization)
            {
                ICustomMobileServiceTableSerialization custom = instance as ICustomMobileServiceTableSerialization;
                if (custom != null)
                {
                    custom.Deserialize(value);
                    return;
                }
            }

            // Get the Mobile Services specific type info
            SerializableType type = SerializableType.Get(instance.GetType());

            // Get the object to deserialize
            JObject obj = value.AsObject();

            if (obj == null)
            {
                throw new ArgumentException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              Resources.MobileServiceTableSerializer_Deserialize_NeedObject,
                              value.Type),
                          "value");
            }

            // Create a set of required members that we can remove from as we
            // process their values from the object.  If there's anything left
            // in the set after processing all of the values, then we weren't
            // given all of our required properties.
            HashSet <SerializableMember> requiredMembers =
                new HashSet <SerializableMember>(type.Members.Values.Where(m => m.IsRequired));

            // Walk through all of the members defined in the object and
            // deserialize them into the instance one at a time
            foreach (KeyValuePair <string, JToken> assignment in obj.GetPropertyValues().OrderBy(a => type.GetMemberOrder(a.Key)))
            {
                // Look up the instance member corresponding to the JSON member
                SerializableMember member = null;
                if (type.Members.TryGetValue(assignment.Key, out member))
                {
                    // Remove the member from the required list (does nothing
                    // if it wasn't present)
                    requiredMembers.Remove(member);

                    // Convert the property value into a CLR value using either
                    // the converter or a standard simple JSON mapping.  This
                    // will throw for JSON arrays or objects.  Also note that
                    // we'll still run the value returned from the converter
                    // through the ChangeType call below to make writing
                    // converters a little easier (but it should be a no-op
                    // for most folks anyway).
                    object propertyValue = null;
                    if (member.Converter != null)
                    {
                        propertyValue = member.Converter.ConvertFromJson(assignment.Value);
                    }
                    else if (!assignment.Value.TryConvert(out propertyValue))
                    {
                        throw new ArgumentException(
                                  string.Format(
                                      CultureInfo.InvariantCulture,
                                      Resources.MobileServiceTableSerializer_Deserialize_CannotDeserializeValue,
                                      assignment.Value.ToString(),
                                      type.Type.FullName,
                                      member.MemberName),
                                  "value");
                    }

                    // Change the type of the value to the desired property
                    // type (mostly to handle things like casting issues) and
                    // set the value on the instance.
                    object convertedValue = TypeExtensions.ChangeType(propertyValue, member.Type);
                    member.SetValue(instance, convertedValue);
                }
            }

            // Ensure we were provided all of the required properties.
            if (requiredMembers.Count > 0)
            {
                throw new SerializationException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              Resources.MobileServiceTableSerializer_Deserialize_MissingRequired,
                              type.Type.FullName,
                              string.Join(", ", requiredMembers.Select(m => m.Name))));
            }
        }