/// <summary>
        /// Writes the ATOM metadata for a single (resource) collection element.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param>
        /// <param name="collection">The collection element to get the metadata for and write it.</param>
        internal static void WriteCollectionMetadata(XmlWriter writer, ODataResourceCollectionInfo collection)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(collection != null, "collection != null");
            Debug.Assert(collection.Name != null, "collection.Name should have been validated at this point");

            // TODO: implement writing the rest of the NYI collection metadata [see AtomPub spec].
            AtomResourceCollectionMetadata metadata = collection.Atom();

            string title = null;

            if (metadata != null)
            {
                title = metadata.Title;
            }

            if (title == null)
            {
                title = collection.Name;
            }

            // <atom:title>title</atom:title>
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title);
        }
예제 #2
0
        public void WriteServiceDocument()
        {
            var msgWriter   = new ODataMessageWriter(_response, _writerSettings, _map.Model);
            var collections = new List <ODataResourceCollectionInfo>();

            foreach (
                var entityContainer in
                _map.Model.EntityContainers().Where(ec => _map.Model.IsDefaultEntityContainer(ec)))
            {
                foreach (var es in entityContainer.EntitySets())
                {
                    var collectionInfo = new ODataResourceCollectionInfo {
                        Url = new Uri(es.Name, UriKind.Relative)
                    };
                    var metadata = new AtomResourceCollectionMetadata {
                        Title = es.Name
                    };
                    collectionInfo.SetAnnotation(metadata);
                    collections.Add(collectionInfo);
                }
            }
            var workspace = new ODataWorkspace {
                Collections = collections
            };

            msgWriter.WriteServiceDocument(workspace);
        }
예제 #3
0
        /// <summary>
        /// Validates a resource collection.
        /// </summary>
        /// <param name="collectionInfo">The resource collection to validate.</param>
        internal static void ValidateResourceCollectionInfo(ODataResourceCollectionInfo collectionInfo)
        {
            DebugUtils.CheckNoExternalCallers();

            // The resource collection name must not be null or empty; it represents the name of the entity set.
            if (string.IsNullOrEmpty(collectionInfo.Name))
            {
                throw new ODataException(Strings.ODataUtils_ResourceCollectionMustHaveName);
            }
        }
        private static ODataResourceCollectionInfo GetODataResourceCollectionInfo(string url, string name)
        {
            ODataResourceCollectionInfo info = new ODataResourceCollectionInfo
            {
                Name = name, // Required for JSON light support
                Url = new Uri(url, UriKind.Relative)
            };

            info.SetAnnotation<AtomResourceCollectionMetadata>(new AtomResourceCollectionMetadata { Title = name });

            return info;
        }
예제 #5
0
        public static AtomResourceCollectionMetadata Atom(this ODataResourceCollectionInfo collection)
        {
            ExceptionUtils.CheckArgumentNotNull <ODataResourceCollectionInfo>(collection, "collection");
            AtomResourceCollectionMetadata annotation = collection.GetAnnotation <AtomResourceCollectionMetadata>();

            if (annotation == null)
            {
                annotation = new AtomResourceCollectionMetadata();
                collection.SetAnnotation <AtomResourceCollectionMetadata>(annotation);
            }
            return(annotation);
        }
예제 #6
0
        private static ODataResourceCollectionInfo GetODataResourceCollectionInfo(string url, string name)
        {
            ODataResourceCollectionInfo info = new ODataResourceCollectionInfo
            {
                Url = new Uri(url, UriKind.Relative)
            };

            info.SetAnnotation <AtomResourceCollectionMetadata>(new AtomResourceCollectionMetadata {
                Title = name
            });

            return(info);
        }
예제 #7
0
        internal ODataWorkspace ReadServiceDocument()
        {
            List <ODataResourceCollectionInfo> sourceList = null;

            base.ReadPayloadStart(false);
            base.JsonReader.ReadStartObject();
            while (base.JsonReader.NodeType == JsonNodeType.Property)
            {
                string strB = base.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal("EntitySets", strB) == 0)
                {
                    if (sourceList != null)
                    {
                        throw new ODataException(Strings.ODataJsonServiceDocumentDeserializer_MultipleEntitySetsPropertiesForServiceDocument);
                    }
                    sourceList = new List <ODataResourceCollectionInfo>();
                    base.JsonReader.ReadStartArray();
                    while (base.JsonReader.NodeType != JsonNodeType.EndArray)
                    {
                        string collectionInfoUrl = base.JsonReader.ReadStringValue();
                        ValidationUtils.ValidateResourceCollectionInfoUrl(collectionInfoUrl);
                        ODataResourceCollectionInfo item = new ODataResourceCollectionInfo {
                            Url = base.ProcessUriFromPayload(collectionInfoUrl, false)
                        };
                        sourceList.Add(item);
                    }
                    base.JsonReader.ReadEndArray();
                }
                else
                {
                    base.JsonReader.SkipValue();
                }
            }
            if (sourceList == null)
            {
                throw new ODataException(Strings.ODataJsonServiceDocumentDeserializer_NoEntitySetsPropertyForServiceDocument);
            }
            base.JsonReader.ReadEndObject();
            base.ReadPayloadEnd(false);
            return(new ODataWorkspace {
                Collections = new ReadOnlyEnumerable <ODataResourceCollectionInfo>(sourceList)
            });
        }
        internal void WriteServiceDocument(DataServiceProviderWrapper provider)
        {
            ODataWorkspace defaultWorkspace = new ODataWorkspace {
                Collections = provider.GetResourceSets().Select <ResourceSetWrapper, ODataResourceCollectionInfo>(delegate(ResourceSetWrapper rs) {
                    ODataResourceCollectionInfo info = new ODataResourceCollectionInfo {
                        Url = new Uri(rs.Name, UriKind.RelativeOrAbsolute)
                    };
                    AtomResourceCollectionMetadata annotation = new AtomResourceCollectionMetadata();
                    AtomTextConstruct construct = new AtomTextConstruct {
                        Text = rs.Name
                    };
                    annotation.Title = construct;
                    info.SetAnnotation <AtomResourceCollectionMetadata>(annotation);
                    return(info);
                })
            };

            this.writer.WriteServiceDocument(defaultWorkspace);
        }
예제 #9
0
        /// <summary>
        /// Reads an atom:title element and adds the new information to <paramref name="collectionInfo"/> and (if ATOM metadata reading is on) <paramref name="collectionMetadata"/>.
        /// </summary>
        /// <param name="collectionMetadata">The collection metadata object to augment, or null if metadata reading is not on.</param>
        /// <param name="collectionInfo">The non-null collection info object being populated.</param>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element - The start of the title element.
        /// Post-Condition: Any                 - The next node after the title element.
        /// </remarks>
        internal void ReadTitleElementInCollection(AtomResourceCollectionMetadata collectionMetadata, ODataResourceCollectionInfo collectionInfo)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(!this.ReadAtomMetadata || collectionMetadata != null, "collectionMetadata parameter should be non-null when ATOM metadata reading is enabled.");
            Debug.Assert(collectionInfo != null, "collectionInfo != null");
            this.AssertXmlCondition(XmlNodeType.Element);
            Debug.Assert(this.XmlReader.LocalName == AtomConstants.AtomTitleElementName, "Expected element named 'title'.");
            Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "Element 'title' should be in the atom namespace.");

            if (collectionInfo.Name != null)
            {
                throw new ODataException(Strings.ODataAtomServiceDocumentMetadataDeserializer_MultipleTitleElementsFound(AtomConstants.AtomPublishingCollectionElementName));
            }

            AtomTextConstruct titleTextConstruct = this.ReadTitleElement();

            collectionInfo.Name = titleTextConstruct.Text;

            if (this.ReadAtomMetadata)
            {
                collectionMetadata.Title = titleTextConstruct;
            }
        }
예제 #10
0
        private ODataResourceCollectionInfo ReadCollectionElement()
        {
            ODataResourceCollectionInfo info = new ODataResourceCollectionInfo();
            string attribute = base.XmlReader.GetAttribute(this.AtomHRefAttributeName, this.EmptyNamespace);

            ValidationUtils.ValidateResourceCollectionInfoUrl(attribute);
            info.Url = base.ProcessUriFromPayload(attribute, base.XmlReader.XmlBaseUri);
            bool enableAtomMetadataReading = base.MessageReaderSettings.EnableAtomMetadataReading;
            AtomResourceCollectionMetadata collectionMetadata = null;

            if (enableAtomMetadataReading)
            {
                collectionMetadata = new AtomResourceCollectionMetadata();
            }
            if (!base.XmlReader.IsEmptyElement)
            {
                base.XmlReader.ReadStartElement();
                do
                {
                    switch (base.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (base.XmlReader.NamespaceEquals(this.AtomPublishingNamespace))
                        {
                            if (base.XmlReader.LocalNameEquals(this.AtomPublishingCategoriesElementName))
                            {
                                if (enableAtomMetadataReading)
                                {
                                    this.ServiceDocumentMetadataDeserializer.ReadCategoriesElementInCollection(collectionMetadata);
                                }
                                else
                                {
                                    base.XmlReader.Skip();
                                }
                            }
                            else
                            {
                                if (!base.XmlReader.LocalNameEquals(this.AtomPublishingAcceptElementName))
                                {
                                    throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInResourceCollection(base.XmlReader.LocalName));
                                }
                                if (enableAtomMetadataReading)
                                {
                                    this.ServiceDocumentMetadataDeserializer.ReadAcceptElementInCollection(collectionMetadata);
                                }
                                else
                                {
                                    base.XmlReader.Skip();
                                }
                            }
                        }
                        else if (base.XmlReader.NamespaceEquals(this.AtomNamespace))
                        {
                            if (enableAtomMetadataReading && base.XmlReader.LocalNameEquals(this.AtomTitleElementName))
                            {
                                this.ServiceDocumentMetadataDeserializer.ReadTitleElementInCollection(collectionMetadata);
                            }
                            else
                            {
                                base.XmlReader.Skip();
                            }
                        }
                        else
                        {
                            base.XmlReader.Skip();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        break;

                    default:
                        base.XmlReader.Skip();
                        break;
                    }
                }while (base.XmlReader.NodeType != XmlNodeType.EndElement);
            }
            base.XmlReader.Read();
            if (enableAtomMetadataReading)
            {
                info.SetAnnotation <AtomResourceCollectionMetadata>(collectionMetadata);
            }
            return(info);
        }
        /// <summary>
        /// Writes the ATOM metadata for a single (resource) collection element.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param>
        /// <param name="collection">The collection element to get the metadata for and write it.</param>
        internal static void WriteCollectionMetadata(XmlWriter writer, ODataResourceCollectionInfo collection)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(collection != null, "collection != null");
            Debug.Assert(collection.Name != null, "collection.Name should have been validated at this point");

            // TODO: implement writing the rest of the NYI collection metadata [see AtomPub spec].
            AtomResourceCollectionMetadata metadata = collection.Atom();

            string title = null;
            if (metadata != null)
            {
                title = metadata.Title;
            }

            if (title == null)
            {
                title = collection.Name;
            }

            // <atom:title>title</atom:title>
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title);
        }
        internal void WriteResourceCollectionMetadata(ODataResourceCollectionInfo collection)
        {
            AtomResourceCollectionMetadata annotation = collection.GetAnnotation <AtomResourceCollectionMetadata>();
            AtomTextConstruct textConstruct           = null;

            if (annotation != null)
            {
                textConstruct = annotation.Title;
            }
            if (base.UseServerFormatBehavior && (textConstruct.Kind == AtomTextConstructKind.Text))
            {
                base.WriteElementWithTextContent("atom", "title", "http://www.w3.org/2005/Atom", textConstruct.Text);
            }
            else
            {
                base.WriteTextConstruct("atom", "title", "http://www.w3.org/2005/Atom", textConstruct);
            }
            if (annotation != null)
            {
                string accept = annotation.Accept;
                if (accept != null)
                {
                    base.WriteElementWithTextContent(string.Empty, "accept", "http://www.w3.org/2007/app", accept);
                }
                AtomCategoriesMetadata categories = annotation.Categories;
                if (categories != null)
                {
                    base.XmlWriter.WriteStartElement(string.Empty, "categories", "http://www.w3.org/2007/app");
                    Uri    href   = categories.Href;
                    bool?  @fixed = categories.Fixed;
                    string scheme = categories.Scheme;
                    IEnumerable <AtomCategoryMetadata> source = categories.Categories;
                    if (href != null)
                    {
                        if ((@fixed.HasValue || (scheme != null)) || ((source != null) && source.Any <AtomCategoryMetadata>()))
                        {
                            throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues);
                        }
                        base.XmlWriter.WriteAttributeString("href", base.UriToUrlAttributeValue(href));
                    }
                    else
                    {
                        if (@fixed.HasValue)
                        {
                            base.XmlWriter.WriteAttributeString("fixed", @fixed.Value ? "yes" : "no");
                        }
                        if (scheme != null)
                        {
                            base.XmlWriter.WriteAttributeString("scheme", scheme);
                        }
                        if (source != null)
                        {
                            foreach (AtomCategoryMetadata metadata3 in source)
                            {
                                base.WriteCategory("atom", metadata3.Term, metadata3.Scheme, metadata3.Label);
                            }
                        }
                    }
                    base.XmlWriter.WriteEndElement();
                }
            }
        }
        /// <summary>
        /// Writes the ATOM metadata for a single (resource) collection element.
        /// </summary>
        /// <param name="collection">The collection element to get the metadata for and write it.</param>
        internal void WriteResourceCollectionMetadata(ODataResourceCollectionInfo collection)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(collection != null, "collection != null");
            Debug.Assert(collection.Url != null, "collection.Url should have been validated at this point");

            AtomResourceCollectionMetadata metadata = collection.GetAnnotation <AtomResourceCollectionMetadata>();

            AtomTextConstruct title = null;

            if (metadata != null)
            {
                title = metadata.Title;
            }

            // The ATOMPUB specification requires a title.
            // <atom:title>title</atom:title>
            // Note that this will write an empty atom:title element even if the title is null.
            if (this.UseServerFormatBehavior && title.Kind == AtomTextConstructKind.Text)
            {
                // For WCF DS server we must not write the type attribute, just a simple <atom:title>title<atom:title>
                this.WriteElementWithTextContent(
                    AtomConstants.NonEmptyAtomNamespacePrefix,
                    AtomConstants.AtomTitleElementName,
                    AtomConstants.AtomNamespace,
                    title.Text);
            }
            else
            {
                this.WriteTextConstruct(AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title);
            }

            if (metadata != null)
            {
                string accept = metadata.Accept;
                if (accept != null)
                {
                    // <app:accept>accept</app:accept>
                    this.WriteElementWithTextContent(
                        string.Empty,
                        AtomConstants.AtomPublishingAcceptElementName,
                        AtomConstants.AtomPublishingNamespace,
                        accept);
                }

                AtomCategoriesMetadata categories = metadata.Categories;
                if (categories != null)
                {
                    // <app:categories>
                    this.XmlWriter.WriteStartElement(string.Empty, AtomConstants.AtomPublishingCategoriesElementName, AtomConstants.AtomPublishingNamespace);

                    Uri    href       = categories.Href;
                    bool?  fixedValue = categories.Fixed;
                    string scheme     = categories.Scheme;
                    IEnumerable <AtomCategoryMetadata> categoriesCollection = categories.Categories;
                    if (href != null)
                    {
                        // Out of line categories document
                        if (fixedValue.HasValue || scheme != null ||
                            (categoriesCollection != null && categoriesCollection.Any()))
                        {
                            throw new ODataException(o.Strings.ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues);
                        }

                        this.XmlWriter.WriteAttributeString(AtomConstants.AtomHRefAttributeName, this.UriToUrlAttributeValue(href));
                    }
                    else
                    {
                        // Inline categories document

                        // fixed='yes|no'
                        if (fixedValue.HasValue)
                        {
                            this.XmlWriter.WriteAttributeString(
                                AtomConstants.AtomPublishingFixedAttributeName,
                                fixedValue.Value ? AtomConstants.AtomPublishingFixedYesValue : AtomConstants.AtomPublishingFixedNoValue);
                        }

                        // scheme='scheme'
                        if (scheme != null)
                        {
                            this.XmlWriter.WriteAttributeString(AtomConstants.AtomCategorySchemeAttributeName, scheme);
                        }

                        if (categoriesCollection != null)
                        {
                            foreach (AtomCategoryMetadata category in categoriesCollection)
                            {
                                // <atom:category/>
                                this.WriteCategory(AtomConstants.NonEmptyAtomNamespacePrefix, category.Term, category.Scheme, category.Label);
                            }
                        }
                    }

                    // </app:categories>
                    this.XmlWriter.WriteEndElement();
                }
            }
        }
        /// <summary>
        /// Read a service document.
        /// This method reads the service document from the input and returns
        /// an <see cref="ODataWorkspace"/> that represents the read service document.
        /// </summary>
        /// <returns>An <see cref="ODataWorkspace"/> representing the read service document.</returns>
        internal ODataWorkspace ReadServiceDocument()
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            this.JsonReader.AssertNotBuffering();

            List <ODataResourceCollectionInfo> collections = null;

            // Read the response wrapper "d"
            this.ReadPayloadStart(false /*isReadingNestedPayload*/);

            // Read the start of the object container around the service document { "EntitySets": ... }
            this.JsonReader.ReadStartObject();

            // read all the properties in the service document object; we ignore all except 'EntitySets'
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();

                if (string.CompareOrdinal(JsonConstants.ODataServiceDocumentEntitySetsName, propertyName) == 0)
                {
                    if (collections != null)
                    {
                        throw new ODataException(Strings.ODataJsonServiceDocumentDeserializer_MultipleEntitySetsPropertiesForServiceDocument);
                    }

                    collections = new List <ODataResourceCollectionInfo>();

                    // read the value of the 'EntitySets' property
                    this.JsonReader.ReadStartArray();

                    while (this.JsonReader.NodeType != JsonNodeType.EndArray)
                    {
                        string collectionUrl = this.JsonReader.ReadStringValue();
                        ValidationUtils.ValidateResourceCollectionInfoUrl(collectionUrl);

                        ODataResourceCollectionInfo collection = new ODataResourceCollectionInfo
                        {
                            Url = this.ProcessUriFromPayload(collectionUrl, /*requireAbsoluteUri*/ false)
                        };

                        collections.Add(collection);
                    }

                    this.JsonReader.ReadEndArray();
                }
                else
                {
                    this.JsonReader.SkipValue();
                }
            }

            if (collections == null)
            {
                throw new ODataException(Strings.ODataJsonServiceDocumentDeserializer_NoEntitySetsPropertyForServiceDocument);
            }

            // Read over the end object (nothing else can happen after all properties have been read)
            this.JsonReader.ReadEndObject();

            // Read the end of the response wrapper "d".
            this.ReadPayloadEnd(false /*isReadingNestedPayload*/);

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput");
            this.JsonReader.AssertNotBuffering();

            return(new ODataWorkspace
            {
                Collections = new ReadOnlyEnumerable <ODataResourceCollectionInfo>(collections)
            });
        }
예제 #15
0
        /// <summary>
        /// Extension method to get the <see cref="AtomResourceCollectionMetadata"/> for an annotatable (resource) collection.
        /// </summary>
        /// <param name="collection">The (resource) collection to get the annotation from.</param>
        /// <returns>An <see cref="AtomResourceCollectionMetadata" /> instance or null if no annotation of that type exists.</returns>
        public static AtomResourceCollectionMetadata Atom(this ODataResourceCollectionInfo collection)
        {
            ExceptionUtils.CheckArgumentNotNull(collection, "collection");

            return(collection.GetAnnotation <AtomResourceCollectionMetadata>());
        }
예제 #16
0
        private ODataWorkspace ReadWorkspace()
        {
            bool enableAtomMetadataReading = base.AtomInputContext.MessageReaderSettings.EnableAtomMetadataReading;

            this.SkipToElementInAtomPublishingNamespace();
            if (base.XmlReader.NodeType == XmlNodeType.EndElement)
            {
                return(null);
            }
            if (!base.XmlReader.LocalNameEquals(this.AtomPublishingWorkspaceElementName))
            {
                throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInServiceDocument(base.XmlReader.LocalName));
            }
            List <ODataResourceCollectionInfo> sourceList = new List <ODataResourceCollectionInfo>();
            AtomWorkspaceMetadata workspaceMetadata       = null;

            if (enableAtomMetadataReading)
            {
                workspaceMetadata = new AtomWorkspaceMetadata();
            }
            if (!base.XmlReader.IsEmptyElement)
            {
                base.XmlReader.ReadStartElement();
                do
                {
                    base.XmlReader.SkipInsignificantNodes();
                    switch (base.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (base.XmlReader.NamespaceEquals(this.AtomPublishingNamespace))
                        {
                            if (!base.XmlReader.LocalNameEquals(this.AtomPublishingCollectionElementName))
                            {
                                throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInWorkspace(base.XmlReader.LocalName));
                            }
                            ODataResourceCollectionInfo item = this.ReadCollectionElement();
                            sourceList.Add(item);
                        }
                        else if (enableAtomMetadataReading && base.XmlReader.NamespaceEquals(this.AtomNamespace))
                        {
                            if (base.XmlReader.LocalNameEquals(this.AtomTitleElementName))
                            {
                                this.ServiceDocumentMetadataDeserializer.ReadTitleElementInWorkspace(workspaceMetadata);
                            }
                            else
                            {
                                base.XmlReader.Skip();
                            }
                        }
                        else
                        {
                            base.XmlReader.Skip();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        break;

                    default:
                        base.XmlReader.Skip();
                        break;
                    }
                }while (base.XmlReader.NodeType != XmlNodeType.EndElement);
            }
            base.XmlReader.Read();
            ODataWorkspace workspace = new ODataWorkspace {
                Collections = new ReadOnlyEnumerable <ODataResourceCollectionInfo>(sourceList)
            };

            if (enableAtomMetadataReading)
            {
                workspace.SetAnnotation <AtomWorkspaceMetadata>(workspaceMetadata);
            }
            return(workspace);
        }
        /// <summary>
        /// Reads a workspace of a service document.
        /// </summary>
        /// <returns>An <see cref="ODataWorkspace"/> representing the workspace of a service document.</returns>
        /// <remarks>
        /// Pre-Condition:  Any    - the next node after the service element.
        /// Post-Condition: Any    - The next node after the workspace element.
        /// </remarks>
        private ODataWorkspace ReadWorkspace()
        {
            Debug.Assert(this.XmlReader != null, "this.XmlReader != null");

            bool enableAtomMetadataReading = this.AtomInputContext.MessageReaderSettings.EnableAtomMetadataReading;

            // skip anything which is not in the ATOM publishing namespace.
            this.SkipToElementInAtomPublishingNamespace();

            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.EndElement);

            // if we already found an EndElement, it means that there is no workspace.
            if (this.XmlReader.NodeType == XmlNodeType.EndElement)
            {
                return(null);
            }

            this.AssertXmlCondition(XmlNodeType.Element);
            Debug.Assert(this.XmlReader.NamespaceEquals(this.AtomPublishingNamespace), "The current element should have been in the Atom publishing namespace.");

            if (!this.XmlReader.LocalNameEquals(this.AtomPublishingWorkspaceElementName))
            {
                throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInServiceDocument(this.XmlReader.LocalName));
            }

            List <ODataResourceCollectionInfo> collections = new List <ODataResourceCollectionInfo>();
            AtomWorkspaceMetadata workspaceMetadata        = null;

            if (enableAtomMetadataReading)
            {
                workspaceMetadata = new AtomWorkspaceMetadata();
            }

            if (!this.XmlReader.IsEmptyElement)
            {
                // read over the 'workspace' element.
                this.XmlReader.ReadStartElement();

                do
                {
                    this.XmlReader.SkipInsignificantNodes();

                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.AtomPublishingNamespace))
                        {
                            if (this.XmlReader.LocalNameEquals(this.AtomPublishingCollectionElementName))
                            {
                                ODataResourceCollectionInfo collection = this.ReadCollectionElement();
                                Debug.Assert(collection != null, "collection != null");
                                collections.Add(collection);
                            }
                            else
                            {
                                // Throw error if we find anything other then a 'collection' element in the Atom publishing namespace.
                                throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInWorkspace(this.XmlReader.LocalName));
                            }
                        }
                        else if (enableAtomMetadataReading && this.XmlReader.NamespaceEquals(this.AtomNamespace))
                        {
                            if (this.XmlReader.LocalNameEquals(this.AtomTitleElementName))
                            {
                                this.ServiceDocumentMetadataDeserializer.ReadTitleElementInWorkspace(workspaceMetadata);
                            }
                            else
                            {
                                this.XmlReader.Skip();
                            }
                        }
                        else
                        {
                            // skip all other elements
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // end of 'workspace' element.
                        break;

                    default:
                        // ignore all other nodes.
                        this.XmlReader.Skip();
                        break;
                    }
                }while (this.XmlReader.NodeType != XmlNodeType.EndElement);
            } // if (!this.XmlReader.IsEmptyElement)

            // read over the end tag of the workspace element or the start tag if the workspace element is empty.
            this.XmlReader.Read();

            ODataWorkspace workspace = new ODataWorkspace
            {
                Collections = new ReadOnlyEnumerable <ODataResourceCollectionInfo>(collections)
            };

            if (enableAtomMetadataReading)
            {
                workspace.SetAnnotation <AtomWorkspaceMetadata>(workspaceMetadata);
            }

            return(workspace);
        }
        /// <summary>
        /// Reads a resource collection within a service document.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The <see cref="DuplicatePropertyNamesChecker"/> to use for parsing annotations within the resource collection object.</param>
        /// <returns>A <see cref="ODataResourceCollectionInfo"/> representing the read resource collection.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.StartObject:     The beginning of the JSON object representing the resource collection.
        ///                 other:                        Will throw with an appropriate message on any other node type encountered.
        /// Post-Condition: JsonNodeType.StartObject:     The beginning of the next resource collection in the array.
        ///                 JsonNodeType.EndArray:        The end of the array.
        ///                 other:                        Any other node type occuring after the end object of the current resource collection. (Would be invalid).
        /// </remarks>
        private ODataResourceCollectionInfo ReadResourceCollection(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.JsonReader.ReadStartObject();
            string[] entitySetName = { null };
            string[] entitySetUrl  = { null };

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                // OData property annotations are not supported in resource collection objects.
                Func <string, object> propertyAnnotationValueReader = annotationName => { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationInResourceCollection(annotationName)); };

                this.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    propertyAnnotationValueReader,
                    (propertyParsingResult, propertyName) =>
                {
                    switch (propertyParsingResult)
                    {
                    case PropertyParsingResult.ODataInstanceAnnotation:
                        throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_InstanceAnnotationInResourceCollection(propertyName));

                    case PropertyParsingResult.CustomInstanceAnnotation:
                        this.JsonReader.SkipValue();
                        break;

                    case PropertyParsingResult.PropertyWithoutValue:
                        throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationWithoutProperty(propertyName));

                    case PropertyParsingResult.MetadataReferenceProperty:
                        throw new ODataException(Strings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName));

                    case PropertyParsingResult.PropertyWithValue:
                        if (string.CompareOrdinal(JsonLightConstants.ODataWorkspaceCollectionNameName, propertyName) == 0)
                        {
                            if (entitySetName[0] != null)
                            {
                                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInResourceCollection(JsonLightConstants.ODataWorkspaceCollectionNameName));
                            }

                            entitySetName[0] = this.JsonReader.ReadStringValue();
                        }
                        else if (string.CompareOrdinal(JsonLightConstants.ODataWorkspaceCollectionUrlName, propertyName) == 0)
                        {
                            if (entitySetUrl[0] != null)
                            {
                                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInResourceCollection(JsonLightConstants.ODataWorkspaceCollectionUrlName));
                            }

                            entitySetUrl[0] = this.JsonReader.ReadStringValue();
                            ValidationUtils.ValidateResourceCollectionInfoUrl(entitySetUrl[0]);
                        }
                        else
                        {
                            throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_UnexpectedPropertyInResourceCollection(propertyName, JsonLightConstants.ODataWorkspaceCollectionNameName, JsonLightConstants.ODataWorkspaceCollectionUrlName));
                        }

                        break;
                    }
                });
            }

            // URL and Name are mandatory
            if (string.IsNullOrEmpty(entitySetName[0]))
            {
                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_MissingRequiredPropertyInResourceCollection(JsonLightConstants.ODataWorkspaceCollectionNameName));
            }

            if (string.IsNullOrEmpty(entitySetUrl[0]))
            {
                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_MissingRequiredPropertyInResourceCollection(JsonLightConstants.ODataWorkspaceCollectionUrlName));
            }

            ODataResourceCollectionInfo collection = new ODataResourceCollectionInfo
            {
                Url  = this.ProcessUriFromPayload(entitySetUrl[0]),
                Name = entitySetName[0],
            };

            this.JsonReader.ReadEndObject();

            return(collection);
        }
        /// <summary>
        /// Read a service document.
        /// This method reads the service document from the input and returns
        /// an <see cref="ODataWorkspace"/> that represents the read service document.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use for the top-level scope.</param>
        /// <returns>An <see cref="ODataWorkspace"/> representing the read service document.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.Property   The property right after the metadata URI property.
        ///                 JsonNodeType.EndObject  The EndObject of the service document.
        /// Post-Condition: Any                     The node after the EndObject of the service document.
        /// </remarks>
        private ODataWorkspace ReadServiceDocumentImplementation(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

            List <ODataResourceCollectionInfo>[] collections = { null };

            // Read all the properties in the service document object; we ignore all except 'value'.
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                // Property annotations are not allowed on the 'value' property, so fail if we see one.
                Func <string, object> readPropertyAnnotationInServiceDoc = annotationName => { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationInServiceDocument(annotationName, JsonLightConstants.ODataValuePropertyName)); };

                this.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    readPropertyAnnotationInServiceDoc,
                    (propertyParsingResult, propertyName) =>
                {
                    switch (propertyParsingResult)
                    {
                    case PropertyParsingResult.ODataInstanceAnnotation:
                        throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_InstanceAnnotationInServiceDocument(propertyName, JsonLightConstants.ODataValuePropertyName));

                    case PropertyParsingResult.CustomInstanceAnnotation:
                        this.JsonReader.SkipValue();
                        break;

                    case PropertyParsingResult.PropertyWithoutValue:
                        throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationWithoutProperty(propertyName));

                    case PropertyParsingResult.PropertyWithValue:
                        if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) == 0)
                        {
                            // Fail if we've already processed a 'value' property.
                            if (collections[0] != null)
                            {
                                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocument(JsonLightConstants.ODataValuePropertyName));
                            }

                            collections[0] = new List <ODataResourceCollectionInfo>();

                            // Read the value of the 'value' property.
                            this.JsonReader.ReadStartArray();
                            DuplicatePropertyNamesChecker resourceCollectionDuplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

                            while (this.JsonReader.NodeType != JsonNodeType.EndArray)
                            {
                                ODataResourceCollectionInfo collection = this.ReadResourceCollection(resourceCollectionDuplicatePropertyNamesChecker);
                                collections[0].Add(collection);
                                resourceCollectionDuplicatePropertyNamesChecker.Clear();
                            }

                            this.JsonReader.ReadEndArray();
                        }
                        else
                        {
                            throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_UnexpectedPropertyInServiceDocument(propertyName, JsonLightConstants.ODataValuePropertyName));
                        }

                        break;

                    case PropertyParsingResult.EndOfObject:
                        break;

                    case PropertyParsingResult.MetadataReferenceProperty:
                        throw new ODataException(Strings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName));
                    }
                });
            }

            if (collections[0] == null)
            {
                throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_MissingValuePropertyInServiceDocument(JsonLightConstants.ODataValuePropertyName));
            }

            // Read over the end object (nothing else can happen after all properties have been read)
            this.JsonReader.ReadEndObject();

            return(new ODataWorkspace
            {
                Collections = new ReadOnlyEnumerable <ODataResourceCollectionInfo>(collections[0])
            });
        }
        /// <summary>
        /// Reads a resource collection element of a workspace of the service document.
        /// </summary>
        /// <returns>An <see cref="ODataResourceCollectionInfo"/> representing the resource collection in a workspace of a service document.</returns>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element - the collection element inside the workspace.
        /// Post-Condition: Any    - The next node after the collection element.
        /// </remarks>
        private ODataResourceCollectionInfo ReadCollectionElement()
        {
            Debug.Assert(this.XmlReader != null, "this.XmlReader != null");
            this.AssertXmlCondition(XmlNodeType.Element);
            Debug.Assert(this.XmlReader.LocalNameEquals(this.AtomPublishingCollectionElementName), "Expected element named 'collection'.");
            Debug.Assert(this.XmlReader.NamespaceEquals(this.AtomPublishingNamespace), "Element 'collection' should be in the atom publishing namespace.");

            ODataResourceCollectionInfo collectionInfo = new ODataResourceCollectionInfo();

            string href = this.XmlReader.GetAttribute(this.AtomHRefAttributeName, this.EmptyNamespace);

            ValidationUtils.ValidateResourceCollectionInfoUrl(href);

            collectionInfo.Url = ProcessUriFromPayload(href, this.XmlReader.XmlBaseUri);
            bool enableAtomMetadataReading = this.MessageReaderSettings.EnableAtomMetadataReading;

            AtomResourceCollectionMetadata collectionMetadata = null;

            if (enableAtomMetadataReading)
            {
                collectionMetadata = new AtomResourceCollectionMetadata();
            }

            if (!this.XmlReader.IsEmptyElement)
            {
                // read over the 'collection' element.
                this.XmlReader.ReadStartElement();

                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.AtomPublishingNamespace))
                        {
                            if (this.XmlReader.LocalNameEquals(this.AtomPublishingCategoriesElementName))
                            {
                                if (enableAtomMetadataReading)
                                {
                                    this.ServiceDocumentMetadataDeserializer.ReadCategoriesElementInCollection(collectionMetadata);
                                }
                                else
                                {
                                    this.XmlReader.Skip();
                                }
                            }
                            else if (this.XmlReader.LocalNameEquals(this.AtomPublishingAcceptElementName))
                            {
                                if (enableAtomMetadataReading)
                                {
                                    this.ServiceDocumentMetadataDeserializer.ReadAcceptElementInCollection(collectionMetadata);
                                }
                                else
                                {
                                    this.XmlReader.Skip();
                                }
                            }
                            else
                            {
                                // Throw error if we find anything other then a 'app:categories' or an 'app:accept' element in the ATOM publishing namespace.
                                throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInResourceCollection(this.XmlReader.LocalName));
                            }
                        }
                        else if (this.XmlReader.NamespaceEquals(this.AtomNamespace))
                        {
                            if (enableAtomMetadataReading && this.XmlReader.LocalNameEquals(this.AtomTitleElementName))
                            {
                                this.ServiceDocumentMetadataDeserializer.ReadTitleElementInCollection(collectionMetadata);
                            }
                            else
                            {
                                // Skip all other elements in the atom namespace
                                this.XmlReader.Skip();
                            }
                        }
                        else
                        {
                            // For now, skip all other elements.
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // end of 'collection' element.
                        break;

                    default:
                        // ignore all other nodes.
                        this.XmlReader.Skip();
                        break;
                    }
                }while (this.XmlReader.NodeType != XmlNodeType.EndElement);
            } // if (!this.XmlReader.IsEmptyElement)

            this.AssertXmlCondition(true, XmlNodeType.EndElement);

            // read over the end tag of the collection element or the start tag if the collection element is empty.
            this.XmlReader.Read();

            if (enableAtomMetadataReading)
            {
                collectionInfo.SetAnnotation(collectionMetadata);
            }

            return(collectionInfo);
        }
예제 #21
0
        /// <summary>
        /// Validates a resource collection.
        /// </summary>
        /// <param name="collectionInfo">The resource collection to validate.</param>
        internal static void ValidateResourceCollectionInfo(ODataResourceCollectionInfo collectionInfo)
        {
            DebugUtils.CheckNoExternalCallers();

            // The resource collection name must not be null or empty; it represents the name of the entity set.
            if (string.IsNullOrEmpty(collectionInfo.Name))
            {
                throw new ODataException(Strings.ODataUtils_ResourceCollectionMustHaveName);
            }
        }