/// <summary> /// Check an XmlElement to see if it includes a specific "Type" attribute. If so, return /// the actual Type associated with that attribute's value. /// </summary> /// <param name="_xml">The XmlElement containing the field's information</param> /// <param name="_defaultType"> /// If there is no Type attribute, then return this value as the "default" /// </param> /// <returns> /// NULL if no Type attribute was found, or the Type object corresponding the value of /// the Type attribute /// </returns> /// <exception cref="InvalidOperationException"> /// Thrown if there is a Type attribute, but that attribute's value cannot be turned /// into a Type object. /// </exception> private Type GetTypeFromXmlOrDefault(XmlElement _xml, Type _defaultType) { var sType = XmlExtensions.GetAttributeValue(_xml, m_context.TypeAttributeName); if (sType == null) // There is no explicit Type specifier (XmlAttribute) { return(_defaultType); } var explicitType = Lib.BetterGetType(sType, true); if (explicitType == null) { // The XML had an explicit Type, but that Type couldn't be found. So... If we // are trying to deserialize a Type that uses EntitySemantics, we assume that // the destination Type is sufficient to figure out what to deserialize. If the // destination Type is wholly inadequate to "receive" the data in the XML, the // application is at fault. For Entities, this type of mismatch is OK. if (CEntityTypeData.UsesEntitySemantics(_defaultType)) { return(_defaultType); } // However, if this isn't using EntitySemantics, then throw an exception as the // Type is unknown. throw new XDeserializationError("An Attribute was found for an Explicit Type, but it could not be turned into a Type: " + sType); } return(explicitType); }
/// <summary> /// The Type uses EntitySemantics. See <see cref="CEntityTypeData"/> for more info on /// EntitySemantics /// </summary> /// <param name="_xml">The XML containing the data</param> /// <param name="_type"> /// The Type that has already been determined to use Entity Semantics /// </param> /// <param name="_workingObject">Where to put the resulting object</param> private void DeserializeUsingEntitySemantics(XmlElement _xml, Type _type, CWorkingObject _workingObject) { var obj = _workingObject.GetExistingOrCreateNew(_type); var typeData = CEntityTypeData.GetTypeData(_type); for (var i = 0; i < typeData.NonCollectionProperties.Length; i++) { var prop = typeData.NonCollectionProperties[i]; var xml = _xml[prop.Name]; if (xml != null) // There was some XmlElement for the property { // This isn't a Field, and we're using EntitySemantics, so use there's // nothing to query PushCurrentField(null); var propVal = FrameworkDeserialize(xml, prop.PropertyType); prop.SetValue(obj, propVal); PopField(); // pop the null we pushed } } for (var i = 0; i < typeData.CollectionProperties.Length; i++) { var colProp = typeData.CollectionProperties[i]; } }
/// <summary> /// Apply any surrogates to the object for serialization /// </summary> /// <param name="_object">The object that may be serialized with a surrogate</param> /// <param name="_elementForObject"> /// The XmlElement that is to receive the object data /// </param> /// <param name="_useType"> /// The Type that the object should be treated as. If NULL, use object.GetType() /// </param> /// <returns> /// TRUE if the serialziation was completed by a surrogate, FALSE if the framework /// should do its job. /// </returns> private bool ApplySurrogates(object _object, XmlElement _elementForObject, Type _useType) { // If nothing is sent in, then do nothing. if (_object == null) { return(false); } // Duplicate References are a "special" kind of built-in surrogate- If this object // has been serialized before, then simply refer to that version and return true. if (HandleDuplicateReferences(_object, _elementForObject)) { return(true); } // Setup var oType = _useType ?? _object.GetType(); var isComplete = false; // Check if the object is a dynamic proxy created by Entity Framework if (CEntityTypeData.UsesEntitySemantics(oType)) { // There are important conventions and differences when dealing with Entities SerializeUsingEntitySemantics(_object, oType, _elementForObject); return(true); } // Check the external surrogate var externalSurrogate = GetExternalSurrogate(oType); if (externalSurrogate != null) { isComplete = externalSurrogate.Serialize(_object, _useType, _elementForObject, this); } if (isComplete) { return(true); } // Check implicit surrogates var typeData = CTypeData.GetTypeData(oType); var impSurrogate = typeData.ImplicitSurrogate; if (impSurrogate != null) { isComplete = impSurrogate.Serialize(_object, _elementForObject, this); } return(isComplete); }
/// <summary> /// Check to see if there are surrogates that handle the deserialization. /// </summary> /// <param name="_xml">The XML containing the object data</param> /// <param name="_type">The TYPE that we're trying to deserialize</param> /// <param name="_workingObject"> /// A "Working Object" that deserializers use to determine if they need to create a new /// object or if they have an object that they can deserialize into. /// </param> /// <returns> /// TRUE if a surrogate was successful in completing the deserialization of the object, /// or FALSE if the surrogates were not able to complete all deserialization /// </returns> private bool ApplySurrogates(XmlElement _xml, Type _type, CWorkingObject _workingObject) { var isComplete = false; _workingObject.WorkingType = _type; // Check for EntitySemantics as a special and overriding Surrogate method The // UseEntitySemantics on the XML element is ignored, as the destination Type gets to // define how it gets deserialized (the attribute may be little more than a Hint to // what happened at serializatiion time) See for more information on EntitySemantics if (CEntityTypeData.UsesEntitySemantics(_type)) { DeserializeUsingEntitySemantics(_xml, _type, _workingObject); return(true); } // Check for external surrogates var externalSurrogate = GetExternalSurrogate(_type); if (externalSurrogate != null) { isComplete = externalSurrogate.Deserialize(_workingObject, _xml, this); } if (isComplete) { return(true); } // Check the Implicit surrogates if the External surrogate(s) didn't finish the // deserialization var typeData = CTypeData.GetTypeData(_type); var implicitSurrogate = typeData.ImplicitSurrogate; if (implicitSurrogate != null && implicitSurrogate.HasSurrogate) { isComplete = implicitSurrogate.Deserialize(_workingObject, _xml, this); } if (isComplete) { return(true); } return(false); }
/// <summary> /// This "different" serializer handles Properties, not Fields, and conforms to the /// conventions found in Microsoft's Entity Framework /// </summary> /// <param name="_object"></param> /// <param name="_useType"></param> /// <param name="_elementForObject"></param> private void SerializeUsingEntitySemantics(object _object, Type _useType, XmlElement _elementForObject) { XmlExtensions.AddAttribute(_elementForObject, m_context.UseEntitySemanticsAttributeName, "1"); // Gets (cached) type data pertinent to serializing an Entity var typeData = CEntityTypeData.GetTypeData(_useType); // First serialize all the "single" properties- No collections for (var i = 0; i < typeData.NonCollectionProperties.Length; i++) { var prop = typeData.NonCollectionProperties[i]; var val = prop.GetValue(_object); FrameworkSerialize(prop.Name, val, _elementForObject, prop.PropertyType); } // Now serialize all the collections which are presumed to be the "Many" in a // Many-To-One relationship. The exact Type of the collection in this object is // irrelevant because the collection should merely implement ICollection for the // deserialization, and the deserialization target class should determine the exact // collection Type, or if its an Interface the PreferredCollectionType on the // AUseEntitySemantics attribute will dictate what to create. for (var i = 0; i < typeData.CollectionProperties.Length; i++) { var col = typeData.CollectionProperties[i]; var collectionElement = XmlExtensions.AddElement(_elementForObject, col.Name); Type elementType = null; // set if the PropertyType is a generic collection if (col.PropertyType.IsGenericType) { elementType = col.PropertyType.GetGenericArguments()[0]; } foreach (var item in col.GetValue(_object) as System.Collections.IEnumerable) { FrameworkSerialize(m_context.ArrayElementName, item, collectionElement, elementType); } } }
/// <summary> /// Create an XmlElement for an object. Do not populate the new element. /// </summary> /// <remarks> /// FieldRenamers are NOT called at this level- the caller of this method needs to /// handle all field renaming /// </remarks> /// <param name="_elementName"> /// The name that should be assigned to the newly created element /// </param> /// <param name="_expectedType"> /// The expected type of the object. Used to decide whether or not to add explicit Type /// data /// </param> /// <param name="_object">The object that is being serialized</param> /// <param name="_parentNode">The XML node that the new node will be a child of</param> /// <returns>An XmlElement with some basic attributes for an object</returns> private XmlElement CreateElementForValue(string _elementName, object _object, XmlNode _parentNode, Type _expectedType) { var fixedElementName = FixMemberName(_elementName); var elem = XmlExtensions.CreateElement(_parentNode, fixedElementName); if (_object == null) { XmlExtensions.AddAttribute(elem, m_context.NullAttributeName, m_context.NullAttributeValue); } else { var oType = _object.GetType(); oType = CEntityTypeData.StripProxyType(oType); if (_expectedType != oType) // There must be a Type attribute added { XmlExtensions.AddAttribute(elem, m_context.TypeAttributeName, oType.AssemblyQualifiedName); } } return(elem); }