Example #1
0
        /// <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);
        }
Example #2
0
        /// <summary>
        /// Using childNodes from an element, deserialize an array by deserializing the
        /// individual elements into the array elements.
        /// </summary>
        /// <param name="_xml">
        /// The XML parent node containing the array elements as childNodes
        /// </param>
        /// <param name="_arrayHelper">The ArrayDeserializationHelper</param>
        private void DeserializeArrayFromElements(XmlElement _xml, CArrayDeserializationHelper _arrayHelper)
        {
            foreach (XmlNode node in _xml.ChildNodes)
            {
                if (!(node is XmlElement elem))
                {
                    throw new XDeserializationError(node.NodeType.ToString() +
                                                    " was the nodetype found (instead of XmlElement) as a child of the array's XML");
                }

                int[] indicies = null;
                var   sIndex   = XmlExtensions.GetAttributeValue(elem, m_context.ArrayIndexAttributeName);
                if (sIndex != null)
                {
                    indicies = sIndex.Split(',').Select(s => int.Parse(s)).ToArray();
                }

                if (indicies != null && indicies.Length > 0)
                {
                    _arrayHelper.SetIndicies(indicies);
                }

                var obj = FrameworkDeserialize(elem, _arrayHelper.ElementType);
                _arrayHelper.Add(obj);
            }
        }
Example #3
0
 /// <summary>
 /// The framework will deserialize the object. No more surrogates or other "exceptional"
 /// behaviour.
 /// </summary>
 /// <param name="_xml"></param>
 /// <param name="_type"></param>
 /// <param name="_workingObject"></param>
 private void HandleDeserialization(XmlElement _xml, Type _type, CWorkingObject _workingObject)
 {
     // Strings are really easy- just return the "InnerText"
     if (_type == TYPEOF_STRING)
     {
         _workingObject.Set(Environment.ExpandEnvironmentVariables(_xml.InnerText));
     }
     // Primitives are also pretty easy, only because of the "Convert" class
     else if (_type.IsPrimitive)
     {
         _workingObject.Set(Convert.ChangeType(_xml.InnerText, _type));
     }
     // Check for an Array
     else if (_type.IsArray || XmlExtensions.HasAttribute(_xml, m_context.ArrayAttributeName))
     {
         DeserializeArray(_xml, _type, _workingObject);
     }
     else if (_type.IsEnum)
     {
         _workingObject.Set(Enum.Parse(_type, _xml.InnerText, false));
     }
     else // Handle ref-type fields and base classes.
     {
         DeserializeReferenceType(_xml, _type, _workingObject);
     }
 }
Example #4
0
        /// <summary>
        /// Check the easiest forms of deserialization- Null and RefTo an object already
        /// deserialized.
        /// </summary>
        /// <param name="_xml">The XML that's being deserialized</param>
        /// <param name="_workObj">
        /// The Object that was deserialized (when the return value is TRUE)
        /// </param>
        /// <returns>
        /// TRUE means that the _workObj parameter contains valid data and nothing further
        /// should be done, FALSE means that no deserialization was performed.
        /// </returns>
        private bool CheckNullAndReference(XmlElement _xml, CWorkingObject _workObj)
        {
            // Check the XML to see if this is a NULL object reference. If it is, then return
            // TRUE.
            if (XmlExtensions.HasAttribute(_xml, m_context.NullAttributeName))
            {
                return(true);
            }

            // Check the XML to see if its referring to some other object.
            var referTo = XmlExtensions.GetAttributeValue(_xml, m_context.ReferToAttributeName);

            if (referTo != null) // There was a reference to another object, so handle it and return that other object.
            {
                // Check the table for the RefID to get the object. The reference must be in the
                // table already because forward-looking references are not supported.
                if (!m_references.TryGetValue(referTo, out var obj))
                {
                    throw new XUnknownReference("All object-references must be to backward-defined objects. The RefID " + referTo + " has not been defined yet.");
                }

                _workObj.Set(obj);
                return(true);
            }

            // Check to see if this element is associating the XML with a reference ID
            var refId = XmlExtensions.GetAttributeValue(_xml, m_context.ReferenceIdAttributeName);

            if (refId != null)
            {
                _workObj.SetRefInfo(this, refId);
            }

            return(false);
        }
Example #5
0
        /// <summary>
        /// Given information about the current state, create an ArrayDeserializationHelper to
        /// help with the deserialization process
        /// </summary>
        /// <param name="_xml">The XML containing the Array information</param>
        /// <param name="_type">The Type of the array expected</param>
        /// <param name="_workingObject">
        /// A "Working Object", likely from a surrogate that didn't complete the deserialization
        /// </param>
        /// <param name="_inferredLength">
        /// The Inferred Length of the array, from a "Condensed Array" already found in the XML
        /// </param>
        /// <returns>
        /// A properly formed <see cref="CArrayDeserializationHelper"/> object.
        /// </returns>
        private CArrayDeserializationHelper CreateArrayDeserializationHelper(XmlElement _xml,
                                                                             Type _type,
                                                                             CWorkingObject _workingObject,
                                                                             int _inferredLength)
        {
            CArrayDeserializationHelper arrayHelper;

            if (_workingObject.IsSet)
            {
                arrayHelper = new CArrayDeserializationHelper(_workingObject.WorkingObject as Array);
            }
            else
            {
                // Make sure that the array type actually is an array and it has an ElementType
                var arrType = _type;
                if (!arrType.IsArray)
                {
                    throw new XDeserializationError(
                              "The Type specified is not an array or it does not have an ElementTypes associated with it- " +
                              arrType.ToString());
                }

                // Get info from the XML
                var sLengths = XmlExtensions.GetAttributeValue(_xml, m_context.ArrayAttributeName);
                var lengths  = sLengths?.Split(',').Select(s => int.Parse(s)).ToArray();

                var sLowerBounds = XmlExtensions.GetAttributeValue(_xml, m_context.ArrayLowerBoundAttribute);
                var lowerBounds  = sLowerBounds?.Split(',').Select(s => int.Parse(s)).ToArray();

                if (lengths == null)
                {
                    if (_inferredLength > -1)
                    {
                        lengths = new int[] { _inferredLength }
                    }
                    ;
                    else
                    {
                        lengths = new int[] { InferArrayLength(_xml) }
                    };                                                    // This assumes a 1-dim array at this point.
                }

                arrayHelper = new CArrayDeserializationHelper(arrType.GetElementType(), lengths, lowerBounds);
            }

            return(arrayHelper);
        }
Example #6
0
        /// <summary>
        /// This routine will try to figure out how large an array is based on the nodes in the
        /// XML
        /// </summary>
        /// <param name="_xml"></param>
        /// <returns></returns>
        private int InferArrayLength(XmlElement _xml)
        {
            // XmlNode node = _xml.SelectSingleNode( @"*/*[@idx][last()]" );
            var index = 0;

            foreach (XmlNode node in _xml.ChildNodes)
            {
                var sIndex = XmlExtensions.GetAttributeValue(node, m_context.ArrayIndexAttributeName);
                if (!string.IsNullOrEmpty(sIndex))
                {
                    index = int.Parse(sIndex);
                }
                index++;
            }

            return(index);
        }
Example #7
0
        /// <summary>
        /// Check to see if the object has been serialized before. If it has, then make sure
        /// that the reference information for it is added.
        /// </summary>
        /// <remarks>This routine has the overloaded</remarks>
        /// <param name="_object">The object that's being serialized</param>
        /// <param name="_elementForObject">
        /// The element that the object is being serialized to
        /// </param>
        /// <returns>TRUE if the object is a duplicate, FALSE if it is a "new" object</returns>
        private bool HandleDuplicateReferences(object _object, XmlElement _elementForObject)
        {
            var oType = _object.GetType();

            if (oType.IsPrimitive)
            {
                return(false);
            }
            if (oType == TYPEOF_STRING && !m_context.DuplicateStringsCanBeReferredTo)
            {
                return(false);
            }
            if (oType.IsEnum)
            {
                return(false);
            }

            if (m_references.TryGetValue(_object, out var refElem)) // The object was serialized already
            {
                if (ReferenceEquals(_elementForObject, refElem))    // If this IS the referenced element, then skip it
                {
                    return(false);
                }

                var refId = XmlExtensions.GetAttributeValue(refElem, m_context.ReferenceIdAttributeName);
                if (refId == null) // The object that was serialized doesn't have its RefID set yet
                {
                    refId = m_refId.ToString();
                    XmlExtensions.AddAttribute(refElem, m_context.ReferenceIdAttributeName, refId);
                    m_refId++;
                }
                // Add the "ReferTo" attribute to the xml
                XmlExtensions.AddAttribute(_elementForObject, m_context.ReferToAttributeName, refId);

                // Remove a "Type" attribute (if it exists) because this becomes redundant with
                // the presence of RefTo
                XmlExtensions.RemoveAttribute(_elementForObject, m_context.TypeAttributeName);

                return(true);
            }

            m_references.Add(_object, _elementForObject);
            return(false);
        }
Example #8
0
        /// <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);
                }
            }
        }
Example #9
0
        /// <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);
        }
Example #10
0
        /// <summary>
        /// Use this method when an Array field needs to be added to the XML serialization
        /// </summary>
        /// <remarks>
        /// For element types that are primitives and strings, build a comma-separated list of
        /// values that should end up taking less space. For all other element types, create
        /// child-elements for each array element.
        /// </remarks>
        /// <param name="_array">The array to add to the XML Element</param>
        /// <param name="_elementToAddTo">The XML Element that is to contain the array</param>
        private void AddArrayToXml(Array _array, XmlElement _elementToAddTo)
        {
            if (_array.Rank != 1)
            {
                AddMultiDimensionalArray(_array, _elementToAddTo);
                return;
            }

            var arrayType   = _array.GetType();
            var elementType = arrayType.GetElementType();

            var count      = _array.Length;
            var lowerBound = _array.GetLowerBound(0);
            var upperBound = _array.GetUpperBound(0);

            XmlExtensions.AddAttribute(_elementToAddTo, m_context.ArrayAttributeName, count);
            if (lowerBound != 0)
            {
                XmlExtensions.AddAttribute(_elementToAddTo, m_context.ArrayLowerBoundAttribute, lowerBound);
            }

            if (elementType.IsPrimitive && !m_context.AllArraysHaveExplicitElements)
            {
                // Helper doesn't care what the element type is, so we screen it first by making
                // sure its a primitive.
                _elementToAddTo.InnerText = Lib.ConvertArrayToString(_array);
            }
            else if (elementType == TYPEOF_STRING && !m_context.AllArraysHaveExplicitElements)
            {
                // Strings could theoretically be treated with the same helper used above IF
                // they never contained commas.
                var str = ConvertStringArrayToCommaList(_array);
                _elementToAddTo.InnerText = str;
            }
            else
            {
                var skipped     = false;
                var elementName = GetNameForCollectionElement();

                for (var i = lowerBound; i <= upperBound; i++)
                {
                    var arrayElementValue = _array.GetValue(i);

                    if (arrayElementValue == null && m_context.RemoveNullValuesFromXml)
                    {
                        skipped = true;
                    }
                    else
                    {
                        var elem = FrameworkSerialize(elementName, arrayElementValue, _elementToAddTo, elementType);

                        if (m_context.ArrayElementsIncludeIndicies || skipped)
                        {
                            XmlExtensions.AddAttribute(elem, m_context.ArrayIndexAttributeName, i);
                        }

                        skipped = false;
                    }
                }
            }
        }