/// <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)))); } }
/// <summary> /// Gets a reference to a table and its data operations. /// </summary> /// <typeparam name="T"> /// The type of the elements in the table. This implies the name of /// the table will either be the type's name or the value of the /// DataTableAttribute applied to the type. /// </typeparam> /// <returns>A reference to the table.</returns> public IMobileServiceTable <T> GetTable <T>() { SerializableType type = SerializableType.Get(typeof(T)); return(new MobileServiceTable <T>(type.TableName, this)); }
/// <summary> /// Serialize an instance to a JSON value. /// </summary> /// <param name="instance">The instance to serialize.</param> /// <returns>The serialized JSON value.</returns> /// <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 JToken Serialize(object instance, bool ignoreCustomSerialization) { if (instance == null) { throw new ArgumentNullException("instance"); } // If the instance implements // ICustomMobileServiceTableSerialization, allow it to handle its // own serialization. if (!ignoreCustomSerialization) { ICustomMobileServiceTableSerialization custom = instance as ICustomMobileServiceTableSerialization; if (custom != null) { return(custom.Serialize()); } } // Get the Mobile Services specific type info SerializableType type = SerializableType.Get(instance.GetType()); // Create a new JSON object to represent the instance JObject obj = new JObject(); foreach (SerializableMember member in type.Members.Values.OrderBy(m => m.Order)) { // Get the value to serialize object value = member.GetValue(instance); if (member.Converter != null) { // If there's a user defined converter, we can apply that // and set the value directly. obj.Set(member.Name, member.Converter.ConvertToJson(value)); } else if (member == type.IdMember && SerializableType.IsDefaultIdValue(value)) { // Special case the ID member so we don't write out any // value if wasn't set (i.e., has a 0 or null value). This // allows us flexibility for the type of the ID column // which is currently a long in SQL but could someday be a // GUID in something like a document database. At some // point we might also change the server to quietly ignore // default values for the ID column on insert. } else if (!obj.TrySet(member.Name, value)) { throw new ArgumentException( string.Format( CultureInfo.InvariantCulture, Resources.MobileServiceTableSerializer_Serialize_UnknownType, member.Name, member.Type.FullName, type.Type.Name), "instance"); } } return(obj); }