SyndicationDeserializer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / SyndicationDeserializer.cs / 1305376 / SyndicationDeserializer.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a deserializer for atom content structured as
//      syndication items or feeds. 
//  
//
// @owner [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Serializers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections.Generic;
    using System.Data.Services.Common; 
    using System.Data.Services.Providers;
    using System.Diagnostics;
    using System.IO;
    using System.Linq; 
    using System.ServiceModel.Syndication;
    using System.Text; 
    using System.Xml; 

    #endregion Namespaces. 

    /// Provides a deserializer for structured content.
    internal class SyndicationDeserializer : Deserializer
    { 
        /// Factory for syndication formatting objects.
        private readonly SyndicationFormatterFactory factory; 
 
        /// reader to read xml from the request stream
        private readonly XmlReader xmlReader; 

        /// Initializes a new  for the specified stream.
        /// Input stream reader from which ATOM content must be read.
        /// Encoding to use for the stream (null to auto-discover). 
        /// Data service for which the deserializer will act.
        /// indicates whether this is a update operation or not 
        /// Factory for formatter objects. 
        /// Tracker to use for modifications.
        internal SyndicationDeserializer(Stream stream, Encoding encoding, IDataService dataService, bool update, SyndicationFormatterFactory factory, UpdateTracker tracker) 
            : base(update, dataService, tracker)
        {
            Debug.Assert(stream != null, "stream != null");
            Debug.Assert(factory != null, "factory != null"); 

            this.factory = factory; 
            this.xmlReader = factory.CreateReader(stream, encoding); 
        }
 
        /// 
        /// Indicates the various form of data in the inline xml element
        /// 
        private enum LinkContent 
        {
            /// If the link element didn't not contain an inline element at all. 
            NoInlineElementSpecified, 

            /// If the link element contained an empty inline element. 
            EmptyInlineElementSpecified,

            /// If the inline element under the link element contained some data.
            InlineElementContainsData 
        }
 
        /// returns the content format for the deserializer 
        protected override ContentFormat ContentFormat
        { 
            get
            {
                return ContentFormat.Atom;
            } 
        }
 
        ///  
        /// Assumes the payload to represent a single object and processes accordingly
        ///  
        /// info about the object being created
        /// the newly formed object that the payload represents
        protected override object CreateSingleObject(SegmentInfo segmentInfo)
        { 
            SyndicationItem item = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), this.xmlReader);
            return this.CreateObject(segmentInfo, true /*topLevel*/, item); 
        } 

        /// Provides an opportunity to clean-up resources. 
        /// 
        /// Whether the call is being made from an explicit call to
        /// IDisposable.Dispose() rather than through the finalizer.
        ///  
        protected override void Dispose(bool disposing)
        { 
            base.Dispose(disposing); 
            if (disposing)
            { 
                this.xmlReader.Close();
            }
        }
 
        /// 
        /// Get the resource referred by the uri in the payload 
        ///  
        /// resource referred by the uri in the payload.
        protected override string GetLinkUriFromPayload() 
        {
            throw Error.NotImplemented();
        }
 
        /// Checks whether the specified item has a payload.
        /// Item to check. 
        /// true if the item has content or links specified; false otherwise. 
        private static bool HasContent(SyndicationItem item)
        { 
            return item.Content != null || item.Links.Count > 0;
        }

        /// Gets the text for the type annotated on the specified . 
        /// Item to read type from.
        /// The text for the type annotated on the specified item; null if none is set. 
        private static string SyndicationItemGetType(SyndicationItem item) 
        {
            Debug.Assert(item != null, "item != null"); 
            SyndicationCategory category = item.Categories.Where(c => c.Scheme == XmlConstants.DataWebSchemeNamespace).FirstOrDefault();
            return (category == null) ? null : category.Name;
        }
 
        /// Reads a SyndicationFeed object from the specified XmlReader.
        /// Formatter to use when reading content. 
        /// Read to read feed from. 
        /// A new SyndicationFeed instance.
        private static SyndicationFeed ReadSyndicationFeed(SyndicationFeedFormatter formatter, XmlReader reader) 
        {
            Debug.Assert(formatter != null, "formatter != null");
            Debug.Assert(reader != null, "reader != null");
 
            try
            { 
                formatter.ReadFrom(reader); 
            }
            catch (XmlException exception) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingFeed(exception.Message), exception);
            }
 
            Debug.Assert(formatter.Feed != null, "formatter.Feed != null");
            return formatter.Feed; 
        } 

        /// Reads a SyndicationItem object from the specified XmlReader. 
        /// Formatter to use when reading content.
        /// Read to read feed from.
        /// A new SyndicationItem instance.
        private static SyndicationItem ReadSyndicationItem(SyndicationItemFormatter formatter, XmlReader reader) 
        {
            Debug.Assert(formatter != null, "formatter != null"); 
            Debug.Assert(reader != null, "reader != null"); 

            try 
            {
                formatter.ReadFrom(reader);
            }
            catch (XmlException exception) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingEntry(exception.Message), exception); 
            } 

            Debug.Assert(formatter.Item != null, "formatter.Item != null"); 
            return formatter.Item;
        }

        ///  
        /// Read the link media type and validate for non open property types
        ///  
        /// media type as specified on the link element. 
        /// property which the link represents.
        /// returns the type parameters specified in the media link. 
        private static string ValidateTypeParameterForNonOpenTypeProperties(string mediaType, ResourceProperty property)
        {
            string typeParameterValue = null;
            if (!String.IsNullOrEmpty(mediaType)) 
            {
                string mime; 
                Encoding encoding; 
                KeyValuePair[] contentTypeParameters = HttpProcessUtility.ReadContentType(mediaType, out mime, out encoding);
                if (mime != XmlConstants.MimeApplicationAtom) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MimeTypeMustBeApplicationAtom(mime, XmlConstants.MimeApplicationAtom));
                }
 
                // If the type parameter is specified, make sure its correct. We do the validation for known properties here
                // and for open-properties, the validation is done if the link is expanded. Otherwise, there is no good way of 
                // doing the validation. 
                typeParameterValue = HttpProcessUtility.GetParameterValue(contentTypeParameters, XmlConstants.AtomTypeAttributeName);
                if (!String.IsNullOrEmpty(typeParameterValue) && property != null) 
                {
                    if (property.Kind == ResourcePropertyKind.ResourceReference)
                    {
                        if (typeParameterValue != XmlConstants.AtomEntryElementName) 
                        {
                            throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); 
                        } 
                    }
                    else if (typeParameterValue != XmlConstants.AtomFeedElementName) 
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName));
                    }
                } 
            }
 
            return typeParameterValue; 
        }
 
        /// 
        /// Gets the XmlReader for the m:properties element under the atom:entry element
        /// 
        /// item to read from 
        /// XmlReader for the m:properties element if found, null otherwise.
        private static XmlReader GetPropertiesReaderFromEntry(SyndicationItem item) 
        { 
            SyndicationElementExtension properties = item.ElementExtensions.Where(p => p.OuterName == XmlConstants.AtomPropertiesElementName && p.OuterNamespace == XmlConstants.DataWebMetadataNamespace).FirstOrDefault();
            if (properties != null) 
            {
                return properties.GetReader();
            }
 
            return null;
        } 
 
        /// 
        /// Gets the XmlReader for the m:properties element under the atom:content element 
        /// 
        /// item to read from
        /// XmlReader for the m:properties element if found, null otherwise.
        private static XmlReader GetPropertiesReaderFromContent(SyndicationItem item) 
        {
            XmlSyndicationContent itemContent = item.Content as XmlSyndicationContent; 
            XmlReader reader = null; 
            if (itemContent != null)
            { 
                string contentType = itemContent.Type;
                if (!WebUtil.CompareMimeType(contentType, XmlConstants.MimeApplicationXml))
                {
                    throw DataServiceException.CreateBadRequestError( 
                        Strings.Syndication_EntryContentTypeUnsupported(contentType));
                } 
 
                bool shouldDispose = false;
                try 
                {
                    reader = itemContent.GetReaderAtContent();
                    WebUtil.XmlReaderEnsureElement(reader);
                    Debug.Assert( 
                        reader.NodeType == XmlNodeType.Element,
                        reader.NodeType.ToString() + " == XmlNodeType.Element -- otherwise XmlSyndicationContent didn't see a 'content' tag"); 
 
                    reader.ReadStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace);
                    if (!reader.IsStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace)) 
                    {
                        shouldDispose = true;
                    }
                } 
                catch
                { 
                    shouldDispose = true; 
                    throw;
                } 
                finally
                {
                    if (shouldDispose)
                    { 
                        WebUtil.Dispose(reader);
                        reader = null; 
                    } 
                }
            } 

            return reader;
        }
 
        /// Applies the properties in the plain XML content to the specified resource.
        /// item to read from. 
        /// Type of resource whose values are being set. 
        /// Properties that have been applied to the 
        /// Target resource. 
        private void ApplyProperties(SyndicationItem item, ResourceType resourceType, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied, object resource)
        {
            Debug.Assert(item != null, "item != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(propertiesApplied != null, "propertiesApplied != null");
            Debug.Assert(resource != null, "resource != null"); 
 
            using (XmlReader propertiesFromEntry = GetPropertiesReaderFromEntry(item))
            using (XmlReader propertiesFromContent = GetPropertiesReaderFromContent(item)) 
            {
                XmlReader reader = null;

                if (resourceType.IsMediaLinkEntry) 
                {
                    if (propertiesFromContent != null) 
                    { 
                        // The server is expecting a MLE payload, however we found a  element under the  element.
                        // The client must assumed the resource type is a non-MLE type and serialized as such. 
                        //
                        // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on
                        // the server where as in fact the properties element is under the wrong node.
                        throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); 
                    }
 
                    reader = propertiesFromEntry; 
                }
                else 
                {
                    if (propertiesFromEntry != null)
                    {
                        // The server is expecting a non-MLE payload, however we found a  element under the  element. 
                        // The client must assumed the resource type is a MLE type and serialized as such.
                        // 
                        // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on 
                        // the server where as in fact the properties element is under the wrong node.
                        throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); 
                    }

                    reader = propertiesFromContent;
                } 

                if (reader != null) 
                { 
                    reader.ReadStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace);
                    PlainXmlDeserializer.ApplyContent(this, reader, resourceType, resource, propertiesApplied, this.MaxObjectCount); 
                }
            }
        }
 
        /// Reads the current object from the .
        /// segmentinfo containing information about the current element that is getting processes 
        /// true if the element currently pointed by the xml reader refers to a top level element 
        /// Item to read from.
        /// returns the clr object with the data populated 
        private object CreateObject(SegmentInfo segmentInfo, bool topLevel, SyndicationItem item)
        {
            Debug.Assert(item != null, "item != null");
            Debug.Assert(topLevel || !this.Update, "deep updates not supported"); 

            this.RecurseEnter(); 
            object result; 

            // update the object count everytime you encounter a new resource 
            this.CheckAndIncrementObjectCount();

            // Process the type annotation.
            ResourceType currentResourceType = this.GetResourceType(item, segmentInfo.TargetResourceType); 
            if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)
            { 
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); 
            }
 
            // We have the actual type info from the payload. Update the request/response DSV if any property is FF mapped with KeepInContent=false.
            this.UpdateAndCheckEpmRequestResponseDSV(currentResourceType, topLevel);

            // Get a resource cookie from the provider. 
            ResourceSetWrapper container;
            if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) 
            { 
                // Open navigation properties are not supported on OpenTypes.
                throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); 
            }
            else
            {
                Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); 
                container = segmentInfo.TargetContainer;
            } 
 
            DataServiceHostWrapper host = this.Service.OperationContext.Host;
            if (this.Update) 
            {
                Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types");

                // Only verify ETag if there is going to be some update applied (that's the idea) 
                // In reality:
                //   - for normal entities (V1 compatible) - don't check ETags if there is no content element. (Same as in V1) 
                //   - for V2 stuff - check ETags always as we can't tell if there's going to be something modified or not 
                //       with EPM properties can be anywhere in the payload and thus even without content there still can be updates
                //       with MLE the properties are not in the content element but in their own element 
                // It's hard to recognize if there's going to be update up front and so this below is an approximation
                //   which seems to be good enough. Note that if we add new ways of handling properties in the content
                //   the condition below might need to change.
                bool verifyETag = 
                    topLevel &&
                    (HasContent(item) || currentResourceType.HasEntityPropertyMappings || currentResourceType.IsMediaLinkEntry); 
                bool replaceResource = topLevel && host.AstoriaHttpVerb == AstoriaVerbs.PUT; 

                // if its a top level resource, then it cannot be null 
                result = this.GetObjectFromSegmentInfo(currentResourceType, segmentInfo, verifyETag, topLevel /*checkForNull*/, replaceResource);
                if (this.Tracker != null)
                {
                    this.Tracker.TrackAction(result, container, UpdateOperations.Change); 
                }
            } 
            else 
            {
                if (segmentInfo.TargetKind == RequestTargetKind.Resource) 
                {
                    DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend);
                }
 
                result = this.Updatable.CreateResource(container.Name, currentResourceType.FullName);
                if (this.Tracker != null) 
                { 
                    this.Tracker.TrackAction(result, container, UpdateOperations.Add);
                } 
            }

            // Process the content in the entry.
            EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied = new EpmContentDeSerializer.EpmAppliedPropertyInfo(); 
            this.ApplyProperties(item, currentResourceType, propertiesApplied, result);
 
            // Perform application of epm properties here 
            if (currentResourceType.HasEntityPropertyMappings)
            { 
                new EpmContentDeSerializer(currentResourceType, result).DeSerialize(
                        item,
                        new EpmContentDeSerializer.EpmContentDeserializerState { IsUpdateOperation = this.Update, Updatable = this.Updatable, Service = this.Service, PropertiesApplied = propertiesApplied });
            } 

            // Process the links in the entry. 
            foreach (SyndicationLink link in item.Links) 
            {
                string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); 

                if (null == navigationPropertyName)
                {
                    continue; 
                }
 
                Deserializer.CheckForBindingInPutOperations(host.AstoriaHttpVerb); 
                Debug.Assert(segmentInfo.TargetContainer != null, "segmentInfo.TargetContainer != null");
                this.ApplyLink(link, segmentInfo.TargetContainer, currentResourceType, result, navigationPropertyName); 
            }

            this.RecurseLeave();
            return result; 
        }
 
        /// Applies the information from a link to the specified resource. 
        /// LinkDescriptor with information to apply.
        /// Set for the target resource. 
        /// Type for the target resource.
        /// Target resource to which information will be applied.
        /// Name of the property that this link represents.
        private void ApplyLink(SyndicationLink link, ResourceSetWrapper resourceSet, ResourceType resourceType, object resource, string propertyName) 
        {
            Debug.Assert(link != null, "link != null"); 
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(resource != null, "resource != null");
 
            ResourceProperty property = resourceType.TryResolvePropertyName(propertyName);
            if (property == null)
            {
                // Open navigation properties are not supported on OpenTypes 
                throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(propertyName));
            } 
 
            if (property.TypeKind != ResourceTypeKind.EntityType)
            { 
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidNavigationPropertyName(propertyName, resourceType.FullName));
            }

            string typeParameterValue = ValidateTypeParameterForNonOpenTypeProperties(link.MediaType, property); 
            LinkContent linkContent = this.HandleLinkContent(link, resource, resourceSet, resourceType, property, typeParameterValue, propertyName);
 
            #region Handle bind/unbind operation 
            // If the href was specified empty or an empty inline element was specified, then we will set the
            // reference to null - this helps in overrriding if there was a default non-value for this property 
            // else if only link element was specified, and then href points to a single result, then we will
            // perform a bind operation
            if ((linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && String.IsNullOrEmpty(link.Uri.OriginalString)) ||
                linkContent == LinkContent.EmptyInlineElementSpecified) 
            {
                // update the object count when you are performing a bind operation 
                this.CheckAndIncrementObjectCount(); 
                if (property != null && property.Kind == ResourcePropertyKind.ResourceSetReference)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
                }

                // For open properties, we will assume that this is a reference property and set it to null 
                this.Updatable.SetReference(resource, propertyName, null);
            } 
            else if (linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && !String.IsNullOrEmpty(link.Uri.OriginalString)) 
            {
                // update the object count when you are performing a bind operation 
                this.CheckAndIncrementObjectCount();

                // If the link points to a reference navigation property, then update the link
                Uri referencedUri = RequestUriProcessor.GetAbsoluteUriFromReference(link.Uri.OriginalString, this.Service.OperationContext); 
                RequestDescription description = RequestUriProcessor.ProcessRequestUri(referencedUri, this.Service);
                if (!description.IsSingleResult) 
                { 
                    if (property != null && property.Kind == ResourcePropertyKind.ResourceReference)
                    { 
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_LinkHrefMustReferToSingleResource(propertyName));
                    }

                    return; 
                }
 
                // no need to check for null. For collection properties, they can never be null and that 
                // check has been added below. For reference properties, if they are null, it means unbind
                // and hence no need to check for null. 
                // Get the resource
                object targetResource = this.Service.GetResource(description, description.SegmentInfos.Length - 1, null);
                if (property.Kind == ResourcePropertyKind.ResourceReference)
                { 
                    this.Updatable.SetReference(resource, propertyName, targetResource);
                } 
                else 
                {
                    WebUtil.CheckResourceExists(targetResource != null, description.LastSegmentInfo.Identifier); 
                    this.Updatable.AddReferenceToCollection(resource, propertyName, targetResource);
                }
            }
            #endregion Handle bind/unbind operation 
        }
 
        /// Gets the type attribute and resolves the type. 
        /// Item from which type attribute needs to be read
        /// Expected base type for the item. 
        /// Resolved type.
        private ResourceType GetResourceType(SyndicationItem item, ResourceType expectedType)
        {
            Debug.Assert(item != null, "item != null"); 
            string typeName = SyndicationItemGetType(item);
            ResourceType resourceType; 
 
            // If the type is not specified in the payload, we assume the type to be the expected type
            if (String.IsNullOrEmpty(typeName)) 
            {
                // check if the expected type takes part in inheritance
                resourceType = expectedType;
                if (this.Service.Provider.HasDerivedTypes(resourceType)) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance); 
                } 
            }
            else 
            {
                // Otherwise, try and resolve the name specified in the payload
                resourceType = this.Service.Provider.TryResolveResourceType(typeName);
                if (resourceType == null) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName)); 
                } 
            }
 
            return resourceType;
        }

        ///  
        /// Handle the contents under the link element
        ///  
        /// syndication link element 
        /// parent resource which contains the link.
        /// resource set of the parent resource 
        /// resource type of the parent resource
        /// property representing the link.
        /// type parameter value as specified in the type attribute.
        /// name of the property that this link represents. 
        /// returns whether there are child elements under link element.
        private LinkContent HandleLinkContent( 
            SyndicationLink link, 
            object parentResource,
            ResourceSetWrapper parentResourceSet, 
            ResourceType parentResourceType,
            ResourceProperty property,
            string typeParameterValue,
            string propertyName) 
        {
            Debug.Assert(parentResource != null, "parent resource cannot be null"); 
            Debug.Assert(property != null, "property != null"); 
            Debug.Assert(link != null, "link != null");
 
            LinkContent linkContent = LinkContent.NoInlineElementSpecified;
            foreach (var e in link.ElementExtensions)
            {
                // link can contain other elements apart from the inline elements. 
                if (e.OuterNamespace != XmlConstants.DataWebMetadataNamespace ||
                    e.OuterName != XmlConstants.AtomInlineElementName) 
                { 
                    continue;
                } 

                // Deep payload cannot be specified for update
                if (this.Update)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported);
                } 
 
                linkContent = LinkContent.EmptyInlineElementSpecified;
                using (XmlReader linkReader = e.GetReader()) 
                {
                    while (linkReader.Read())
                    {
                        if (linkReader.NodeType == XmlNodeType.Element) 
                        {
                            string elementName = linkReader.LocalName; 
                            string namespaceUri = linkReader.NamespaceURI; 
                            if (namespaceUri != XmlConstants.AtomNamespace)
                            { 
                                throw DataServiceException.CreateBadRequestError(
                                    Strings.BadRequest_InlineElementMustContainValidElement(
                                        elementName,
                                        XmlConstants.AtomInlineElementName, 
                                        XmlConstants.AtomFeedElementName,
                                        XmlConstants.AtomEntryElementName)); 
                            } 

                            ResourceSetWrapper targetSet = this.Service.Provider.GetContainer(parentResourceSet, parentResourceType, property); 
                            if (targetSet == null)
                            {
                                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
                            } 

                            // FeatureVersion needs to be 2.0 if any of the property in the types contained in the resource set has KeepInContent false 
                            this.RequestDescription.UpdateAndCheckEpmFeatureVersion(targetSet, this.Service); 

                            linkContent = LinkContent.InlineElementContainsData; 
                            if (elementName == XmlConstants.AtomEntryElementName)
                            {
                                if (property.Kind != ResourcePropertyKind.ResourceReference)
                                { 
                                    throw DataServiceException.CreateBadRequestError(Strings.Syndication_EntryElementForReferenceProperties(e.OuterName, propertyName));
                                } 
 
                                // Make sure if the media type is specified. If its specified, it should better be link
                                SyndicationItem propertyItem; 
                                propertyItem = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), linkReader);

                                SegmentInfo propertySegment = CreateSegment(property, propertyName, targetSet, true /* singleResult */);
                                Debug.Assert(propertySegment.TargetKind != RequestTargetKind.OpenProperty, "Open navigation properties are not supported on OpenTypes."); 

                                object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, propertyItem); 
                                this.Updatable.SetReference(parentResource, propertyName, propertyValue); 
                            }
                            else if (elementName == XmlConstants.AtomFeedElementName) 
                            {
                                    if (property.Kind != ResourcePropertyKind.ResourceSetReference)
                                    {
                                        throw DataServiceException.CreateBadRequestError(Strings.Syndication_FeedElementForCollections(e.OuterName, propertyName)); 
                                    }
 
                                SyndicationFeed propertyFeed; 
                                propertyFeed = ReadSyndicationFeed(this.factory.CreateSyndicationFeedFormatter(), linkReader);
 
                                SegmentInfo propertySegment = CreateSegment(property, propertyName, targetSet, false /* singleResult */);
                                Debug.Assert(propertySegment.TargetKind != RequestTargetKind.OpenProperty, "Open navigation properties are not supported on OpenTypes.");

                                foreach (SyndicationItem item in propertyFeed.Items) 
                                {
                                    object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, item); 
                                    if (propertyValue == null) 
                                    {
                                        if (propertySegment.ProjectedProperty != null && 
                                            propertySegment.ProjectedProperty.Kind == ResourcePropertyKind.ResourceSetReference)
                                        {
                                            throw DataServiceException.CreateBadRequestError(
                                                Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); 
                                        }
                                    } 
 
                                    Debug.Assert(
                                            propertySegment.TargetSource == RequestTargetSource.Property && 
                                            propertySegment.TargetKind == RequestTargetKind.Resource &&
                                            propertySegment.SingleResult == false,
                                            "Must be navigation set property.");
 
                                    this.Updatable.AddReferenceToCollection(parentResource, propertyName, propertyValue);
                                } 
                            } 
                            else
                            { 
                                throw DataServiceException.CreateBadRequestError(
                                    Strings.BadRequest_InlineElementMustContainValidElement(
                                        elementName,
                                        XmlConstants.AtomInlineElementName, 
                                        XmlConstants.AtomFeedElementName,
                                        XmlConstants.AtomEntryElementName)); 
                            } 
                        }
                    } 
                }
            }

            return linkContent; 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a deserializer for atom content structured as
//      syndication items or feeds. 
//  
//
// @owner [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Serializers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections.Generic;
    using System.Data.Services.Common; 
    using System.Data.Services.Providers;
    using System.Diagnostics;
    using System.IO;
    using System.Linq; 
    using System.ServiceModel.Syndication;
    using System.Text; 
    using System.Xml; 

    #endregion Namespaces. 

    /// Provides a deserializer for structured content.
    internal class SyndicationDeserializer : Deserializer
    { 
        /// Factory for syndication formatting objects.
        private readonly SyndicationFormatterFactory factory; 
 
        /// reader to read xml from the request stream
        private readonly XmlReader xmlReader; 

        /// Initializes a new  for the specified stream.
        /// Input stream reader from which ATOM content must be read.
        /// Encoding to use for the stream (null to auto-discover). 
        /// Data service for which the deserializer will act.
        /// indicates whether this is a update operation or not 
        /// Factory for formatter objects. 
        /// Tracker to use for modifications.
        internal SyndicationDeserializer(Stream stream, Encoding encoding, IDataService dataService, bool update, SyndicationFormatterFactory factory, UpdateTracker tracker) 
            : base(update, dataService, tracker)
        {
            Debug.Assert(stream != null, "stream != null");
            Debug.Assert(factory != null, "factory != null"); 

            this.factory = factory; 
            this.xmlReader = factory.CreateReader(stream, encoding); 
        }
 
        /// 
        /// Indicates the various form of data in the inline xml element
        /// 
        private enum LinkContent 
        {
            /// If the link element didn't not contain an inline element at all. 
            NoInlineElementSpecified, 

            /// If the link element contained an empty inline element. 
            EmptyInlineElementSpecified,

            /// If the inline element under the link element contained some data.
            InlineElementContainsData 
        }
 
        /// returns the content format for the deserializer 
        protected override ContentFormat ContentFormat
        { 
            get
            {
                return ContentFormat.Atom;
            } 
        }
 
        ///  
        /// Assumes the payload to represent a single object and processes accordingly
        ///  
        /// info about the object being created
        /// the newly formed object that the payload represents
        protected override object CreateSingleObject(SegmentInfo segmentInfo)
        { 
            SyndicationItem item = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), this.xmlReader);
            return this.CreateObject(segmentInfo, true /*topLevel*/, item); 
        } 

        /// Provides an opportunity to clean-up resources. 
        /// 
        /// Whether the call is being made from an explicit call to
        /// IDisposable.Dispose() rather than through the finalizer.
        ///  
        protected override void Dispose(bool disposing)
        { 
            base.Dispose(disposing); 
            if (disposing)
            { 
                this.xmlReader.Close();
            }
        }
 
        /// 
        /// Get the resource referred by the uri in the payload 
        ///  
        /// resource referred by the uri in the payload.
        protected override string GetLinkUriFromPayload() 
        {
            throw Error.NotImplemented();
        }
 
        /// Checks whether the specified item has a payload.
        /// Item to check. 
        /// true if the item has content or links specified; false otherwise. 
        private static bool HasContent(SyndicationItem item)
        { 
            return item.Content != null || item.Links.Count > 0;
        }

        /// Gets the text for the type annotated on the specified . 
        /// Item to read type from.
        /// The text for the type annotated on the specified item; null if none is set. 
        private static string SyndicationItemGetType(SyndicationItem item) 
        {
            Debug.Assert(item != null, "item != null"); 
            SyndicationCategory category = item.Categories.Where(c => c.Scheme == XmlConstants.DataWebSchemeNamespace).FirstOrDefault();
            return (category == null) ? null : category.Name;
        }
 
        /// Reads a SyndicationFeed object from the specified XmlReader.
        /// Formatter to use when reading content. 
        /// Read to read feed from. 
        /// A new SyndicationFeed instance.
        private static SyndicationFeed ReadSyndicationFeed(SyndicationFeedFormatter formatter, XmlReader reader) 
        {
            Debug.Assert(formatter != null, "formatter != null");
            Debug.Assert(reader != null, "reader != null");
 
            try
            { 
                formatter.ReadFrom(reader); 
            }
            catch (XmlException exception) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingFeed(exception.Message), exception);
            }
 
            Debug.Assert(formatter.Feed != null, "formatter.Feed != null");
            return formatter.Feed; 
        } 

        /// Reads a SyndicationItem object from the specified XmlReader. 
        /// Formatter to use when reading content.
        /// Read to read feed from.
        /// A new SyndicationItem instance.
        private static SyndicationItem ReadSyndicationItem(SyndicationItemFormatter formatter, XmlReader reader) 
        {
            Debug.Assert(formatter != null, "formatter != null"); 
            Debug.Assert(reader != null, "reader != null"); 

            try 
            {
                formatter.ReadFrom(reader);
            }
            catch (XmlException exception) 
            {
                throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingEntry(exception.Message), exception); 
            } 

            Debug.Assert(formatter.Item != null, "formatter.Item != null"); 
            return formatter.Item;
        }

        ///  
        /// Read the link media type and validate for non open property types
        ///  
        /// media type as specified on the link element. 
        /// property which the link represents.
        /// returns the type parameters specified in the media link. 
        private static string ValidateTypeParameterForNonOpenTypeProperties(string mediaType, ResourceProperty property)
        {
            string typeParameterValue = null;
            if (!String.IsNullOrEmpty(mediaType)) 
            {
                string mime; 
                Encoding encoding; 
                KeyValuePair[] contentTypeParameters = HttpProcessUtility.ReadContentType(mediaType, out mime, out encoding);
                if (mime != XmlConstants.MimeApplicationAtom) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MimeTypeMustBeApplicationAtom(mime, XmlConstants.MimeApplicationAtom));
                }
 
                // If the type parameter is specified, make sure its correct. We do the validation for known properties here
                // and for open-properties, the validation is done if the link is expanded. Otherwise, there is no good way of 
                // doing the validation. 
                typeParameterValue = HttpProcessUtility.GetParameterValue(contentTypeParameters, XmlConstants.AtomTypeAttributeName);
                if (!String.IsNullOrEmpty(typeParameterValue) && property != null) 
                {
                    if (property.Kind == ResourcePropertyKind.ResourceReference)
                    {
                        if (typeParameterValue != XmlConstants.AtomEntryElementName) 
                        {
                            throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); 
                        } 
                    }
                    else if (typeParameterValue != XmlConstants.AtomFeedElementName) 
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName));
                    }
                } 
            }
 
            return typeParameterValue; 
        }
 
        /// 
        /// Gets the XmlReader for the m:properties element under the atom:entry element
        /// 
        /// item to read from 
        /// XmlReader for the m:properties element if found, null otherwise.
        private static XmlReader GetPropertiesReaderFromEntry(SyndicationItem item) 
        { 
            SyndicationElementExtension properties = item.ElementExtensions.Where(p => p.OuterName == XmlConstants.AtomPropertiesElementName && p.OuterNamespace == XmlConstants.DataWebMetadataNamespace).FirstOrDefault();
            if (properties != null) 
            {
                return properties.GetReader();
            }
 
            return null;
        } 
 
        /// 
        /// Gets the XmlReader for the m:properties element under the atom:content element 
        /// 
        /// item to read from
        /// XmlReader for the m:properties element if found, null otherwise.
        private static XmlReader GetPropertiesReaderFromContent(SyndicationItem item) 
        {
            XmlSyndicationContent itemContent = item.Content as XmlSyndicationContent; 
            XmlReader reader = null; 
            if (itemContent != null)
            { 
                string contentType = itemContent.Type;
                if (!WebUtil.CompareMimeType(contentType, XmlConstants.MimeApplicationXml))
                {
                    throw DataServiceException.CreateBadRequestError( 
                        Strings.Syndication_EntryContentTypeUnsupported(contentType));
                } 
 
                bool shouldDispose = false;
                try 
                {
                    reader = itemContent.GetReaderAtContent();
                    WebUtil.XmlReaderEnsureElement(reader);
                    Debug.Assert( 
                        reader.NodeType == XmlNodeType.Element,
                        reader.NodeType.ToString() + " == XmlNodeType.Element -- otherwise XmlSyndicationContent didn't see a 'content' tag"); 
 
                    reader.ReadStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace);
                    if (!reader.IsStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace)) 
                    {
                        shouldDispose = true;
                    }
                } 
                catch
                { 
                    shouldDispose = true; 
                    throw;
                } 
                finally
                {
                    if (shouldDispose)
                    { 
                        WebUtil.Dispose(reader);
                        reader = null; 
                    } 
                }
            } 

            return reader;
        }
 
        /// Applies the properties in the plain XML content to the specified resource.
        /// item to read from. 
        /// Type of resource whose values are being set. 
        /// Properties that have been applied to the 
        /// Target resource. 
        private void ApplyProperties(SyndicationItem item, ResourceType resourceType, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied, object resource)
        {
            Debug.Assert(item != null, "item != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(propertiesApplied != null, "propertiesApplied != null");
            Debug.Assert(resource != null, "resource != null"); 
 
            using (XmlReader propertiesFromEntry = GetPropertiesReaderFromEntry(item))
            using (XmlReader propertiesFromContent = GetPropertiesReaderFromContent(item)) 
            {
                XmlReader reader = null;

                if (resourceType.IsMediaLinkEntry) 
                {
                    if (propertiesFromContent != null) 
                    { 
                        // The server is expecting a MLE payload, however we found a  element under the  element.
                        // The client must assumed the resource type is a non-MLE type and serialized as such. 
                        //
                        // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on
                        // the server where as in fact the properties element is under the wrong node.
                        throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); 
                    }
 
                    reader = propertiesFromEntry; 
                }
                else 
                {
                    if (propertiesFromEntry != null)
                    {
                        // The server is expecting a non-MLE payload, however we found a  element under the  element. 
                        // The client must assumed the resource type is a MLE type and serialized as such.
                        // 
                        // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on 
                        // the server where as in fact the properties element is under the wrong node.
                        throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); 
                    }

                    reader = propertiesFromContent;
                } 

                if (reader != null) 
                { 
                    reader.ReadStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace);
                    PlainXmlDeserializer.ApplyContent(this, reader, resourceType, resource, propertiesApplied, this.MaxObjectCount); 
                }
            }
        }
 
        /// Reads the current object from the .
        /// segmentinfo containing information about the current element that is getting processes 
        /// true if the element currently pointed by the xml reader refers to a top level element 
        /// Item to read from.
        /// returns the clr object with the data populated 
        private object CreateObject(SegmentInfo segmentInfo, bool topLevel, SyndicationItem item)
        {
            Debug.Assert(item != null, "item != null");
            Debug.Assert(topLevel || !this.Update, "deep updates not supported"); 

            this.RecurseEnter(); 
            object result; 

            // update the object count everytime you encounter a new resource 
            this.CheckAndIncrementObjectCount();

            // Process the type annotation.
            ResourceType currentResourceType = this.GetResourceType(item, segmentInfo.TargetResourceType); 
            if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)
            { 
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); 
            }
 
            // We have the actual type info from the payload. Update the request/response DSV if any property is FF mapped with KeepInContent=false.
            this.UpdateAndCheckEpmRequestResponseDSV(currentResourceType, topLevel);

            // Get a resource cookie from the provider. 
            ResourceSetWrapper container;
            if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) 
            { 
                // Open navigation properties are not supported on OpenTypes.
                throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); 
            }
            else
            {
                Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); 
                container = segmentInfo.TargetContainer;
            } 
 
            DataServiceHostWrapper host = this.Service.OperationContext.Host;
            if (this.Update) 
            {
                Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types");

                // Only verify ETag if there is going to be some update applied (that's the idea) 
                // In reality:
                //   - for normal entities (V1 compatible) - don't check ETags if there is no content element. (Same as in V1) 
                //   - for V2 stuff - check ETags always as we can't tell if there's going to be something modified or not 
                //       with EPM properties can be anywhere in the payload and thus even without content there still can be updates
                //       with MLE the properties are not in the content element but in their own element 
                // It's hard to recognize if there's going to be update up front and so this below is an approximation
                //   which seems to be good enough. Note that if we add new ways of handling properties in the content
                //   the condition below might need to change.
                bool verifyETag = 
                    topLevel &&
                    (HasContent(item) || currentResourceType.HasEntityPropertyMappings || currentResourceType.IsMediaLinkEntry); 
                bool replaceResource = topLevel && host.AstoriaHttpVerb == AstoriaVerbs.PUT; 

                // if its a top level resource, then it cannot be null 
                result = this.GetObjectFromSegmentInfo(currentResourceType, segmentInfo, verifyETag, topLevel /*checkForNull*/, replaceResource);
                if (this.Tracker != null)
                {
                    this.Tracker.TrackAction(result, container, UpdateOperations.Change); 
                }
            } 
            else 
            {
                if (segmentInfo.TargetKind == RequestTargetKind.Resource) 
                {
                    DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend);
                }
 
                result = this.Updatable.CreateResource(container.Name, currentResourceType.FullName);
                if (this.Tracker != null) 
                { 
                    this.Tracker.TrackAction(result, container, UpdateOperations.Add);
                } 
            }

            // Process the content in the entry.
            EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied = new EpmContentDeSerializer.EpmAppliedPropertyInfo(); 
            this.ApplyProperties(item, currentResourceType, propertiesApplied, result);
 
            // Perform application of epm properties here 
            if (currentResourceType.HasEntityPropertyMappings)
            { 
                new EpmContentDeSerializer(currentResourceType, result).DeSerialize(
                        item,
                        new EpmContentDeSerializer.EpmContentDeserializerState { IsUpdateOperation = this.Update, Updatable = this.Updatable, Service = this.Service, PropertiesApplied = propertiesApplied });
            } 

            // Process the links in the entry. 
            foreach (SyndicationLink link in item.Links) 
            {
                string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); 

                if (null == navigationPropertyName)
                {
                    continue; 
                }
 
                Deserializer.CheckForBindingInPutOperations(host.AstoriaHttpVerb); 
                Debug.Assert(segmentInfo.TargetContainer != null, "segmentInfo.TargetContainer != null");
                this.ApplyLink(link, segmentInfo.TargetContainer, currentResourceType, result, navigationPropertyName); 
            }

            this.RecurseLeave();
            return result; 
        }
 
        /// Applies the information from a link to the specified resource. 
        /// LinkDescriptor with information to apply.
        /// Set for the target resource. 
        /// Type for the target resource.
        /// Target resource to which information will be applied.
        /// Name of the property that this link represents.
        private void ApplyLink(SyndicationLink link, ResourceSetWrapper resourceSet, ResourceType resourceType, object resource, string propertyName) 
        {
            Debug.Assert(link != null, "link != null"); 
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(resource != null, "resource != null");
 
            ResourceProperty property = resourceType.TryResolvePropertyName(propertyName);
            if (property == null)
            {
                // Open navigation properties are not supported on OpenTypes 
                throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(propertyName));
            } 
 
            if (property.TypeKind != ResourceTypeKind.EntityType)
            { 
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidNavigationPropertyName(propertyName, resourceType.FullName));
            }

            string typeParameterValue = ValidateTypeParameterForNonOpenTypeProperties(link.MediaType, property); 
            LinkContent linkContent = this.HandleLinkContent(link, resource, resourceSet, resourceType, property, typeParameterValue, propertyName);
 
            #region Handle bind/unbind operation 
            // If the href was specified empty or an empty inline element was specified, then we will set the
            // reference to null - this helps in overrriding if there was a default non-value for this property 
            // else if only link element was specified, and then href points to a single result, then we will
            // perform a bind operation
            if ((linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && String.IsNullOrEmpty(link.Uri.OriginalString)) ||
                linkContent == LinkContent.EmptyInlineElementSpecified) 
            {
                // update the object count when you are performing a bind operation 
                this.CheckAndIncrementObjectCount(); 
                if (property != null && property.Kind == ResourcePropertyKind.ResourceSetReference)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
                }

                // For open properties, we will assume that this is a reference property and set it to null 
                this.Updatable.SetReference(resource, propertyName, null);
            } 
            else if (linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && !String.IsNullOrEmpty(link.Uri.OriginalString)) 
            {
                // update the object count when you are performing a bind operation 
                this.CheckAndIncrementObjectCount();

                // If the link points to a reference navigation property, then update the link
                Uri referencedUri = RequestUriProcessor.GetAbsoluteUriFromReference(link.Uri.OriginalString, this.Service.OperationContext); 
                RequestDescription description = RequestUriProcessor.ProcessRequestUri(referencedUri, this.Service);
                if (!description.IsSingleResult) 
                { 
                    if (property != null && property.Kind == ResourcePropertyKind.ResourceReference)
                    { 
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_LinkHrefMustReferToSingleResource(propertyName));
                    }

                    return; 
                }
 
                // no need to check for null. For collection properties, they can never be null and that 
                // check has been added below. For reference properties, if they are null, it means unbind
                // and hence no need to check for null. 
                // Get the resource
                object targetResource = this.Service.GetResource(description, description.SegmentInfos.Length - 1, null);
                if (property.Kind == ResourcePropertyKind.ResourceReference)
                { 
                    this.Updatable.SetReference(resource, propertyName, targetResource);
                } 
                else 
                {
                    WebUtil.CheckResourceExists(targetResource != null, description.LastSegmentInfo.Identifier); 
                    this.Updatable.AddReferenceToCollection(resource, propertyName, targetResource);
                }
            }
            #endregion Handle bind/unbind operation 
        }
 
        /// Gets the type attribute and resolves the type. 
        /// Item from which type attribute needs to be read
        /// Expected base type for the item. 
        /// Resolved type.
        private ResourceType GetResourceType(SyndicationItem item, ResourceType expectedType)
        {
            Debug.Assert(item != null, "item != null"); 
            string typeName = SyndicationItemGetType(item);
            ResourceType resourceType; 
 
            // If the type is not specified in the payload, we assume the type to be the expected type
            if (String.IsNullOrEmpty(typeName)) 
            {
                // check if the expected type takes part in inheritance
                resourceType = expectedType;
                if (this.Service.Provider.HasDerivedTypes(resourceType)) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance); 
                } 
            }
            else 
            {
                // Otherwise, try and resolve the name specified in the payload
                resourceType = this.Service.Provider.TryResolveResourceType(typeName);
                if (resourceType == null) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName)); 
                } 
            }
 
            return resourceType;
        }

        ///  
        /// Handle the contents under the link element
        ///  
        /// syndication link element 
        /// parent resource which contains the link.
        /// resource set of the parent resource 
        /// resource type of the parent resource
        /// property representing the link.
        /// type parameter value as specified in the type attribute.
        /// name of the property that this link represents. 
        /// returns whether there are child elements under link element.
        private LinkContent HandleLinkContent( 
            SyndicationLink link, 
            object parentResource,
            ResourceSetWrapper parentResourceSet, 
            ResourceType parentResourceType,
            ResourceProperty property,
            string typeParameterValue,
            string propertyName) 
        {
            Debug.Assert(parentResource != null, "parent resource cannot be null"); 
            Debug.Assert(property != null, "property != null"); 
            Debug.Assert(link != null, "link != null");
 
            LinkContent linkContent = LinkContent.NoInlineElementSpecified;
            foreach (var e in link.ElementExtensions)
            {
                // link can contain other elements apart from the inline elements. 
                if (e.OuterNamespace != XmlConstants.DataWebMetadataNamespace ||
                    e.OuterName != XmlConstants.AtomInlineElementName) 
                { 
                    continue;
                } 

                // Deep payload cannot be specified for update
                if (this.Update)
                { 
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported);
                } 
 
                linkContent = LinkContent.EmptyInlineElementSpecified;
                using (XmlReader linkReader = e.GetReader()) 
                {
                    while (linkReader.Read())
                    {
                        if (linkReader.NodeType == XmlNodeType.Element) 
                        {
                            string elementName = linkReader.LocalName; 
                            string namespaceUri = linkReader.NamespaceURI; 
                            if (namespaceUri != XmlConstants.AtomNamespace)
                            { 
                                throw DataServiceException.CreateBadRequestError(
                                    Strings.BadRequest_InlineElementMustContainValidElement(
                                        elementName,
                                        XmlConstants.AtomInlineElementName, 
                                        XmlConstants.AtomFeedElementName,
                                        XmlConstants.AtomEntryElementName)); 
                            } 

                            ResourceSetWrapper targetSet = this.Service.Provider.GetContainer(parentResourceSet, parentResourceType, property); 
                            if (targetSet == null)
                            {
                                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
                            } 

                            // FeatureVersion needs to be 2.0 if any of the property in the types contained in the resource set has KeepInContent false 
                            this.RequestDescription.UpdateAndCheckEpmFeatureVersion(targetSet, this.Service); 

                            linkContent = LinkContent.InlineElementContainsData; 
                            if (elementName == XmlConstants.AtomEntryElementName)
                            {
                                if (property.Kind != ResourcePropertyKind.ResourceReference)
                                { 
                                    throw DataServiceException.CreateBadRequestError(Strings.Syndication_EntryElementForReferenceProperties(e.OuterName, propertyName));
                                } 
 
                                // Make sure if the media type is specified. If its specified, it should better be link
                                SyndicationItem propertyItem; 
                                propertyItem = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), linkReader);

                                SegmentInfo propertySegment = CreateSegment(property, propertyName, targetSet, true /* singleResult */);
                                Debug.Assert(propertySegment.TargetKind != RequestTargetKind.OpenProperty, "Open navigation properties are not supported on OpenTypes."); 

                                object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, propertyItem); 
                                this.Updatable.SetReference(parentResource, propertyName, propertyValue); 
                            }
                            else if (elementName == XmlConstants.AtomFeedElementName) 
                            {
                                    if (property.Kind != ResourcePropertyKind.ResourceSetReference)
                                    {
                                        throw DataServiceException.CreateBadRequestError(Strings.Syndication_FeedElementForCollections(e.OuterName, propertyName)); 
                                    }
 
                                SyndicationFeed propertyFeed; 
                                propertyFeed = ReadSyndicationFeed(this.factory.CreateSyndicationFeedFormatter(), linkReader);
 
                                SegmentInfo propertySegment = CreateSegment(property, propertyName, targetSet, false /* singleResult */);
                                Debug.Assert(propertySegment.TargetKind != RequestTargetKind.OpenProperty, "Open navigation properties are not supported on OpenTypes.");

                                foreach (SyndicationItem item in propertyFeed.Items) 
                                {
                                    object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, item); 
                                    if (propertyValue == null) 
                                    {
                                        if (propertySegment.ProjectedProperty != null && 
                                            propertySegment.ProjectedProperty.Kind == ResourcePropertyKind.ResourceSetReference)
                                        {
                                            throw DataServiceException.CreateBadRequestError(
                                                Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); 
                                        }
                                    } 
 
                                    Debug.Assert(
                                            propertySegment.TargetSource == RequestTargetSource.Property && 
                                            propertySegment.TargetKind == RequestTargetKind.Resource &&
                                            propertySegment.SingleResult == false,
                                            "Must be navigation set property.");
 
                                    this.Updatable.AddReferenceToCollection(parentResource, propertyName, propertyValue);
                                } 
                            } 
                            else
                            { 
                                throw DataServiceException.CreateBadRequestError(
                                    Strings.BadRequest_InlineElementMustContainValidElement(
                                        elementName,
                                        XmlConstants.AtomInlineElementName, 
                                        XmlConstants.AtomFeedElementName,
                                        XmlConstants.AtomEntryElementName)); 
                            } 
                        }
                    } 
                }
            }

            return linkContent; 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK