/// <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); }
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); }
/// <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; }
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); }
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); }
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); }
/// <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; } }
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); }
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) }); }
/// <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>()); }
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); }