/// <summary>
 /// Deserializes the attributes from the <paramref name="reader"/> and sets values on <paramref name="element"/>
 /// </summary>
 /// <param name="reader">Current content reader.</param>
 /// <param name="currentRoot">Segment which has child attribute segments.</param>
 /// <param name="element">Current object.</param>
 /// <param name="resourceType">Resource type of <paramref name="element"/></param>
 private void DeserializeAttributes(XmlReader reader, EpmTargetPathSegment currentRoot, object element, ResourceType resourceType)
 {
     foreach (var attributeSegment in currentRoot.SubSegments.Where(s => s.IsAttribute))
     {
         String attribValue = WebUtil.GetAttributeEx(reader, attributeSegment.SegmentName.Substring(1), attributeSegment.SegmentNamespaceUri);
         if (attribValue != null)
         {
             if (!EpmContentDeSerializerBase.Match(attributeSegment, this.PropertiesApplied))
             {
                 resourceType.SetEpmValue(attributeSegment, element, attribValue, this);
             }
         }
     }
 }
Beispiel #2
0
        /// <summary>
        /// Given a collection of <paramref name="segments"/> corresponding to a property access path
        /// on the <paramref name="element"/> object, sets the <paramref name="propertyValue"/> on the property
        /// </summary>
        /// <param name="segments">Property access path where each element is a property name</param>
        /// <param name="resourceType">Resource type for which to set the property</param>
        /// <param name="element">Object on which to set property</param>
        /// <param name="propertyValue">Value of property</param>
        /// <param name="currentIndex">Index of the current segment being looked at</param>
        /// <param name="deserializer">Current deserializer</param>
        internal void SetPropertyValueFromPath(
            String[] segments,
            ResourceType resourceType,
            object element,
            object propertyValue,
            int currentIndex,
            EpmContentDeSerializerBase deserializer)
        {
            String currentSegment = segments[currentIndex];

            ResourceProperty clientProp = resourceType.TryResolvePropertyName(currentSegment);
            ResourceType propertyType;
            if (clientProp == null && resourceType.IsOpenType == false)
            {
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(currentSegment, resourceType.FullName));
            }

            // If this is a open property OR we do not have to do type conversion for primitive types,
            // read the type from the payload.
            if (clientProp == null ||
                (!deserializer.Service.Configuration.EnableTypeConversion && clientProp.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive))
            {
                String foundTypeName = deserializer.PropertiesApplied.MapPropertyToType(String.Join("/", segments, 0, currentIndex + 1));
                if (foundTypeName != null)
                {
                    propertyType = WebUtil.TryResolveResourceType(deserializer.Service.Provider, foundTypeName);
                    if (propertyType == null)
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(foundTypeName));
                    }

                    if (propertyType.ResourceTypeKind == ResourceTypeKind.EntityType)
                    {
                        throw DataServiceException.CreateBadRequestError(
                            Strings.PlainXml_EntityTypeNotSupported(propertyType.FullName));
                    }
                }
                else
                {
                    propertyType = ResourceType.PrimitiveStringResourceType;
                }
            }
            else
            {
                propertyType = clientProp.ResourceType;
            }

            object currentValue;

            // Re-construct the source path to add the newly applied property
            string sourcePath = string.Join("/", segments, 0, currentIndex + 1);

            switch (propertyType.ResourceTypeKind)
            {
                case ResourceTypeKind.ComplexType:
                    if (!deserializer.PropertiesApplied.Lookup(sourcePath))
                    {
                        // Complex types are treated as atomic and we never allow merging of properties belonging to
                        // a complex type.  In other words, we either update the whole complex type or not at all, 
                        // never just a subset of its properties.  If the complex property has not been applied yet
                        // we create a new instance then apply its property mappings.
                        currentValue = deserializer.Updatable.CreateResource(null, propertyType.FullName);
                        ResourceType.SetEpmProperty(element, currentSegment, currentValue, sourcePath, deserializer);
                    }
                    else
                    {
                        // We've already created a new instance of the complex property by now, reuse the same instance.
                        currentValue = deserializer.Updatable.GetValue(element, currentSegment);
                        Debug.Assert(currentValue != null, "currentValue != null -- we should never be here if the complex property were null.");
                    }

                    this.SetPropertyValueFromPath(segments, propertyType, currentValue, propertyValue, ++currentIndex, deserializer);
                    break;
                case ResourceTypeKind.EntityType:
                    throw DataServiceException.CreateBadRequestError(
                        Strings.PlainXml_NavigationPropertyNotSupported(clientProp.Name));
                default:
                    Debug.Assert(
                        propertyType.ResourceTypeKind == ResourceTypeKind.Primitive,
                        "property.TypeKind == ResourceTypeKind.Primitive -- metadata shouldn't return " + propertyType.ResourceTypeKind);

                    currentValue = PlainXmlDeserializer.ConvertValuesForXml(propertyValue, currentSegment, propertyType.InstanceType);

                    // Do not try to update the property if it is a key property
                    if (!deserializer.IsUpdateOperation || clientProp == null || !clientProp.IsOfKind(ResourcePropertyKind.Key))
                    {
                        ResourceType.SetEpmProperty(element, currentSegment, currentValue, sourcePath, deserializer);
                    }

                    break;
            }
        }
Beispiel #3
0
 /// <summary>
 /// Sets the value <paramref name="propertyValue"/> on the <paramref name="currentValue"/> object
 /// </summary>
 /// <param name="currentSegment">Target path segment containing the corresponding attribute information</param>
 /// <param name="currentValue">Object on which to set property</param>
 /// <param name="propertyValue">Value to be set</param>
 /// <param name="deserializer">Current deserializer</param>
 internal void SetEpmValue(EpmTargetPathSegment currentSegment, Object currentValue, object propertyValue, EpmContentDeSerializerBase deserializer)
 {
     if (currentSegment.EpmInfo.Attribute.KeepInContent == false)
     {
         this.SetPropertyValueFromPath(
                 currentSegment.EpmInfo.Attribute.SourcePath.Split('/'),
                 this,
                 currentValue,
                 propertyValue,
                 0,
                 deserializer);
     }
 }
Beispiel #4
0
 /// <summary>
 /// Sets a mapped property value and mark its source path as applied
 /// </summary>
 /// <param name="element">Object on which to set the property</param>
 /// <param name="propertyName">Name of the property</param>
 /// <param name="propertyValue">Value of the property</param>
 /// <param name="sourcePath">Source mapping path for the property to be set</param>
 /// <param name="deserializer">Current deserializer</param>
 private static void SetEpmProperty(object element, string propertyName, object propertyValue, string sourcePath, EpmContentDeSerializerBase deserializer)
 {
     deserializer.Updatable.SetValue(element, propertyName, propertyValue);
     deserializer.PropertiesApplied.AddAppliedProperty(sourcePath, false);
 }
Beispiel #5
0
        /// <summary>Used for deserializing each of syndication specific content nodes</summary>
        /// <param name="currentRoot">Node in the target path being processed</param>
        /// <param name="resourceType">ResourceType</param>
        /// <param name="element">object being deserialized</param>
        private void DeSerialize(EpmTargetPathSegment currentRoot, ResourceType resourceType, object element)
        {
            foreach (EpmTargetPathSegment newRoot in currentRoot.SubSegments)
            {
                if (newRoot.HasContent)
                {
                    if (!EpmContentDeSerializerBase.Match(newRoot, this.PropertiesApplied))
                    {
                        switch (newRoot.EpmInfo.Attribute.TargetSyndicationItem)
                        {
                        case SyndicationItemProperty.AuthorEmail:
                            if (this.Item.Authors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Authors[0].Email, this);
                            }

                            break;

                        case SyndicationItemProperty.AuthorName:
                            if (this.Item.Authors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Authors[0].Name, this);
                            }

                            break;

                        case SyndicationItemProperty.AuthorUri:
                            if (this.Item.Authors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Authors[0].Uri, this);
                            }

                            break;

                        case SyndicationItemProperty.ContributorEmail:
                            if (this.Item.Contributors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Contributors[0].Email, this);
                            }

                            break;

                        case SyndicationItemProperty.ContributorName:
                            if (this.Item.Contributors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Contributors[0].Name, this);
                            }

                            break;

                        case SyndicationItemProperty.ContributorUri:
                            if (this.Item.Contributors.Count > 0)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Contributors[0].Uri, this);
                            }

                            break;

                        case SyndicationItemProperty.Updated:
                            // If this.Item.LastUpdatedTime == DateTimeOffset.MinValue we assume that the date has not been provided
                            // by the user. This is the same assumption Syndication Api does (see Atom10FeedFormatter.WriteItemContents()).
                            // If the date was not provided by the user we should not touch it - otherwise the response will not be
                            // compatible with response sent for the same request and the same resource type but having KeepInContent set to true
                            if (this.Item.LastUpdatedTime > DateTimeOffset.MinValue)
                            {
                                resourceType.SetEpmValue(newRoot, element, XmlConvert.ToString(this.Item.LastUpdatedTime), this);
                            }

                            break;

                        case SyndicationItemProperty.Published:
                            if (this.Item.PublishDate > DateTimeOffset.MinValue)
                            {
                                resourceType.SetEpmValue(newRoot, element, XmlConvert.ToString(this.Item.PublishDate), this);
                            }

                            break;

                        case SyndicationItemProperty.Rights:
                            if (this.Item.Copyright != null)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Copyright.Text, this);
                            }

                            break;

                        case SyndicationItemProperty.Summary:
                            if (this.Item.Summary != null)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Summary.Text, this);
                            }

                            break;

                        case SyndicationItemProperty.Title:
                            if (this.Item.Title != null)
                            {
                                resourceType.SetEpmValue(newRoot, element, this.Item.Title.Text, this);
                            }

                            break;

                        default:
                            Debug.Fail("Unhandled SyndicationItemProperty enum value - should never get here.");
                            break;
                        }
                    }
                }
                else
                {
                    this.DeSerialize(newRoot, resourceType, element);
                }
            }
        }
        /// <summary>Called internally to deserialize each <see cref="SyndicationElementExtension"/></summary>
        /// <param name="reader">XmlReader for current extension</param>
        /// <param name="currentRoot">Node in the target path being processed</param>
        /// <param name="resourceType">ResourceType</param>
        /// <param name="element">object being deserialized</param>
        private void DeSerialize(XmlReader reader, EpmTargetPathSegment currentRoot, ResourceType resourceType, object element)
        {
            EpmValueBuilder currentValue = new EpmValueBuilder();

            do
            {
                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    if (currentRoot.HasContent)
                    {
                        // Throw an exception that we hit mixed-content.
                        // <contentElement>value<someElement /></contentElement>
                        // <contentElement><someElement />value</contentElement>
                        throw DataServiceException.CreateBadRequestError(Strings.EpmDeserialize_MixedContent(resourceType.FullName));
                    }

                    String elementName           = reader.LocalName;
                    String namespaceUri          = reader.NamespaceURI;
                    EpmTargetPathSegment newRoot = currentRoot.SubSegments
                                                   .SingleOrDefault(s => s.SegmentNamespaceUri == namespaceUri && s.SegmentName == elementName);
                    if (newRoot == null)
                    {
                        WebUtil.SkipToEnd(reader, elementName, namespaceUri);
                        continue;
                    }

                    currentRoot = newRoot;

                    this.DeserializeAttributes(reader, currentRoot, element, resourceType);

                    if (currentRoot.HasContent)
                    {
                        if (reader.IsEmptyElement)
                        {
                            if (!EpmContentDeSerializerBase.Match(currentRoot, this.PropertiesApplied))
                            {
                                resourceType.SetEpmValue(currentRoot, element, String.Empty, this);
                            }

                            currentRoot = currentRoot.ParentSegment;
                        }
                    }

                    break;

                case XmlNodeType.CDATA:
                case XmlNodeType.Text:
                case XmlNodeType.SignificantWhitespace:
                    if (!currentRoot.HasContent)
                    {
                        // Throw an exception that we hit mixed-content.
                        // <noContentElement>value<contentElement>value</contentElement></noContentElement>
                        // <noContentElement><contentElement>value</contentElement>value</noContentElement>
                        throw DataServiceException.CreateBadRequestError(Strings.EpmDeserialize_MixedContent(resourceType.FullName));
                    }

                    currentValue.Append(reader.Value);
                    break;

                case XmlNodeType.EndElement:
                    if (currentRoot.HasContent)
                    {
                        if (!EpmContentDeSerializerBase.Match(currentRoot, this.PropertiesApplied))
                        {
                            resourceType.SetEpmValue(currentRoot, element, currentValue.Value, this);
                        }
                    }

                    currentRoot = currentRoot.ParentSegment;
                    currentValue.Reset();
                    break;

                case XmlNodeType.Comment:
                case XmlNodeType.Whitespace:
                    break;

                case XmlNodeType.None:
                case XmlNodeType.XmlDeclaration:
                case XmlNodeType.Attribute:
                case XmlNodeType.EndEntity:
                case XmlNodeType.EntityReference:
                case XmlNodeType.Entity:
                case XmlNodeType.Document:
                case XmlNodeType.DocumentType:
                case XmlNodeType.DocumentFragment:
                case XmlNodeType.Notation:
                case XmlNodeType.ProcessingInstruction:
                    throw DataServiceException.CreateBadRequestError(Strings.EpmDeserialize_InvalidXmlEntity);
                }
            }while (currentRoot.ParentSegment != null && reader.Read());
        }