/// <summary> /// Initializes a new instance of <c>SerializationContext</c> class. /// </summary> /// <param name="serializable">The object which is serialized/deserialized.</param> /// <param name="member">The member whose value is serialized/deserialized.</param> /// <param name="mapping">The mapping info for the member.</param> /// <param name="useMembers">The list of members to use.</param> /// <param name="deserializeAs">The type that the value should be deserialized into.</param> /// <param name="emitTypeInfo">Specifies whether the type info should be emitted when serializing the object.</param> /// <param name="version">The version of the object that should be used when serializing the object.</param> /// <param name="formatProvider">The format provider passed to the serializer.</param> /// <param name="resolver">The xml namespace resolver.</param> public SerializationContext( IXPathSerializable serializable, SerializableMemberInfo member, Mapping mapping, MemberInfo[] useMembers, Type deserializeAs = null, bool emitTypeInfo = false, int version = 0, IFormatProvider formatProvider = null, XmlNamespaceManager resolver = null) { if (serializable == null) { throw new ArgumentNullException("serializable"); } if (member == null) { throw new ArgumentNullException("member"); } if (mapping == null) { throw new ArgumentNullException("mapping"); } this.Serializable = serializable; this.Member = member; this.Mapping = mapping; this.FormatProvider = formatProvider; this.EmitTypeInfo = emitTypeInfo; this.DeserializeAs = deserializeAs; this.NamespaceResolver = resolver; this.UseMembers = useMembers; }
/// <summary> /// Serializes an object to xml. /// </summary> /// <param name="serializable">The object to serialize.</param> /// <param name="emitTypeInfo">Specifies whether the type info should be emitted when serializing the object.</param> /// <param name="version">The version of the object that should be used when serializing the object.</param> /// <param name="provider">An object that supplies culture-specific formatting information.</param> /// <returns>The xml string with the serialized object.</returns> /// <exception cref="SerializationException">Is thrown if the serialization cannot be performed.</exception> public static string ToXml( this IXPathSerializable serializable, bool emitTypeInfo = false, int version = 0, IFormatProvider provider = null) { return(ToXmlInternal( new XDocument(), serializable, objectsAlreadySerialized: new HashSet <object>(), useMembers: null, parentMapping: null, emitTypeInfo: emitTypeInfo, version: version, provider: provider, resolver: null).ToString()); }
private static MemberInfo[] GetFilterMembers <TFilter>(IXPathSerializable serializable, MemberFilter <TFilter> filter) { var members = new List <MemberInfo>(); if (filter == null) { return(members.ToArray()); } foreach (var expression in filter) { MemberExpression propertyExpression; var unary = expression.Body as UnaryExpression; if (unary != null) { // In this case the return type of the property was not object, // so .Net wrapped the expression inside of a unary Convert() expression that casts it to type object. // In this case, the Operand of the Convert expression has the original expression. propertyExpression = unary.Operand as MemberExpression; } else { propertyExpression = expression.Body as MemberExpression; } if (propertyExpression != null) { var propertyName = propertyExpression.Member.Name; var field = propertyExpression.Member.DeclaringType.GetField(propertyName); var property = propertyExpression.Member.DeclaringType.GetProperty(propertyName); if (field != null) { members.Add(field); } if (property != null) { members.Add(property); } } } return(members.ToArray()); }
/// <summary> /// Serializes an object to xml. /// </summary> /// <param name="serializable">The object to serialize.</param> /// <param name="filter">The member filter.</param> /// <param name="emitTypeInfo">Specifies whether the type info should be emitted when serializing the object.</param> /// <param name="version">The version of the object that should be used when serializing the object.</param> /// <param name="provider">An object that supplies culture-specific formatting information.</param> /// <returns>The xml document with the serialized object.</returns> /// <exception cref="SerializationException">Is thrown if the serialization cannot be performed.</exception> public static XDocument ToXmlDocument <TFilter>( this IXPathSerializable serializable, MemberFilter <TFilter> filter = null, bool emitTypeInfo = false, int version = 0, IFormatProvider provider = null) { var useMembers = GetFilterMembers <TFilter>(serializable, filter); return(ToXmlInternal( new XDocument(), serializable, objectsAlreadySerialized: new HashSet <object>(), useMembers: useMembers, parentMapping: null, emitTypeInfo: emitTypeInfo, version: version, provider: provider, resolver: null)); }
private static IXPathSerializable LoadFromXmlInternal( XDocument document, IXPathSerializable serializable, MemberInfo[] useMembers, Mapping parentMapping, int version, IFormatProvider provider, XmlNamespaceManager resolver) { // Initialize namespace resolver from class attributes if (resolver == null) { resolver = new XmlNamespaceManager(new NameTable()); } var namespaceAttributes = serializable.GetType().GetCustomAttributes(typeof(NamespacePrefixAttribute), true); foreach (NamespacePrefixAttribute namespaceAttribute in namespaceAttributes) { resolver.AddNamespace(namespaceAttribute.Prefix, namespaceAttribute.Uri); } var typeInfo = SerializableTypeInfo.GetTypeInfo(serializable.GetType()); var membersToLoad = typeInfo.Members.Where(x => useMembers == null || useMembers.Length == 0 || useMembers.Contains(x.MemberInfo)); LoadMembersFromXml( document, serializable, membersToLoad.ToArray(), useMembers, parentMapping, version, provider, resolver); return(serializable); }
private static void LoadMembersFromXml( XDocument document, IXPathSerializable serializable, SerializableMemberInfo[] membersToLoad, MemberInfo[] useMembers, Mapping parentMapping, int version, IFormatProvider provider, XmlNamespaceManager resolver) { foreach (var member in membersToLoad) { // Skip non-serializable members if (member.GetSingleCustomAttribute <NotForSerializationAttribute>() != null) { continue; } // Check if the member is serializable in the current version int serializedFromVersion = 0; var versionAttribute = member.GetSingleCustomAttribute <SerializedFromVersionAttribute>(); if (versionAttribute != null) { serializedFromVersion = versionAttribute.Version; } if (version < serializedFromVersion) { continue; } var mapping = member.GetMapping(serializable.GetType(), parentMapping); var mappedElement = document.Root.XPathSelectElement(mapping.ElementXPath, resolver); bool mappedToAttributeWhichIsNotFound = !String.IsNullOrWhiteSpace(mapping.AttributeName) && (mappedElement == null || mappedElement.Attribute(XPathHelper.ConvertToXName(mapping.AttributeName, resolver)) == null); // Ensure mandatory xml elements/attributes are present if (mapping.IsXmlMandatory) { if (mappedElement == null) { throw new SerializationException( String.Format( "Cannot deserialize {0} '{1}', type '{2}'. Could not find the element with path '{3}'", member.MemeberTypeString, member.Name, serializable.GetType(), mapping.ElementXPath)); } else if (mappedToAttributeWhichIsNotFound) { throw new SerializationException( String.Format( "Cannot deserialize {0} '{1}', type '{2}'. Could not find the attribute '{3}' of the element with path '{4}'", member.MemeberTypeString, member.Name, serializable.GetType(), mapping.AttributeName, mapping.ElementXPath)); } } // Short-circuit for nulls if (mappedElement == null || mappedToAttributeWhichIsNotFound) { member.SetValue(serializable, null); continue; } if (string.IsNullOrWhiteSpace(mapping.AttributeName)) { var isNullAttribute = mappedElement.Attribute(Constants.NullValueAttributeName); if (isNullAttribute != null) { member.SetValue(serializable, null); continue; } } // Determine the type of the deserialized value Type emittedType = null; if (mappedElement != null && string.IsNullOrWhiteSpace(mapping.AttributeName)) { var typeAttribute = mappedElement.Attribute(Constants.TypeInfoAttributeName); if (typeAttribute != null) { emittedType = Type.GetType(typeAttribute.Value); // TODO: handle all kind of exceptions } } Type deserializeAs; if (emittedType != null) { deserializeAs = emittedType; } else { deserializeAs = member.MemberType; } var context = new SerializationContext( serializable, member, mapping, useMembers, deserializeAs, version: version, formatProvider: provider, resolver: resolver); if (deserializeAs.IsArray && !mapping.AsBase64) { LoadArrayMemberFromXml(mappedElement, context); } else if (typeof(IXPathSerializable).IsAssignableFrom(deserializeAs)) { LoadXPathSerializableMemberFromXml(document, context); } else { LoadSimpleMemberFromXml(mappedElement, context); } } }
private static void SerializeMembers( XDocument document, IXPathSerializable serializable, HashSet <object> objectsAlreadySerialized, SerializableMemberInfo[] membersToSerialize, MemberInfo[] useMembers = null, Mapping parentMapping = null, bool emitTypeInfo = false, int version = 0, IFormatProvider provider = null, XmlNamespaceManager resolver = null) { foreach (var member in membersToSerialize) { // Skip non-serializable members if (member.GetSingleCustomAttribute <NotForSerializationAttribute>() != null) { continue; } // Check if the member is serializable in the current version int serializedFromVersion = 0; var versionAttribute = member.GetSingleCustomAttribute <SerializedFromVersionAttribute>(); if (versionAttribute != null) { serializedFromVersion = versionAttribute.Version; } if (version < serializedFromVersion) { continue; } var mapping = member.GetMapping(serializable.GetType(), parentMapping); object value = member.GetValue(serializable); // Remember the type in case we need to emit it into the Xml Type deserializeAs = null; if (value != null && emitTypeInfo) { deserializeAs = value.GetType(); } var context = new SerializationContext(serializable, member, mapping, useMembers, deserializeAs, emitTypeInfo, version, provider, resolver); // TODO: what if mandatory? if (value != null && value.GetType().IsArray&& !mapping.AsBase64) { SerializeArrayMember(document, value, context, objectsAlreadySerialized); } else { if (value != null && typeof(IXPathSerializable).IsAssignableFrom(value.GetType())) { SerializeXPathSerializableMember(document, value, context, objectsAlreadySerialized); } else { SerializeSimpleMember(document, value, context); } } } }
private static XDocument ToXmlInternal( XDocument document, IXPathSerializable serializable, HashSet <object> objectsAlreadySerialized, MemberInfo[] useMembers, Mapping parentMapping, bool emitTypeInfo, int version, IFormatProvider provider, XmlNamespaceManager resolver) { // Take care of circular references if (objectsAlreadySerialized.Contains(serializable)) { throw new SerializationException( String.Format("A circular reference was detected while serializing an object of type '{0}'", serializable.GetType())); } else { objectsAlreadySerialized.Add(serializable); } if (document == null) { document = new XDocument(); } // Initialize namespace resolver from class attributes if (resolver == null) { resolver = new XmlNamespaceManager(new NameTable()); } var namespaceAttributes = serializable.GetType().GetCustomAttributes(typeof(NamespacePrefixAttribute), true); foreach (NamespacePrefixAttribute namespaceAttribute in namespaceAttributes) { resolver.AddNamespace(namespaceAttribute.Prefix, namespaceAttribute.Uri); } // Ensure minimal xml structure var minimalXmlAttributes = serializable.GetType().GetCustomAttributes(typeof(MinimalXmlStructureAttribute), true); if (minimalXmlAttributes != null) { foreach (MinimalXmlStructureAttribute minimalXmlAttribute in minimalXmlAttributes) { string xPath = minimalXmlAttribute.ElementXPath; if (String.IsNullOrWhiteSpace(xPath)) { xPath = XmlConvert.EncodeName(serializable.GetType().Name); } XmlOperations.GetOrCreateElement(document, xPath, resolver); } } var typeInfo = SerializableTypeInfo.GetTypeInfo(serializable.GetType()); var membersToSerialize = typeInfo.Members.Where(x => useMembers == null || useMembers.Length == 0 || useMembers.Contains(x.MemberInfo)); SerializeMembers( document, serializable, objectsAlreadySerialized, membersToSerialize.ToArray(), useMembers, parentMapping, emitTypeInfo, version, provider, resolver); // Return resulting document return(document); }