/// <summary> /// Writes a element (EntitySet, Singleton or FunctionImport) in service document. /// </summary> /// <param name="serviceDocumentElement">The element in service document to write.</param> /// <param name="kind">Kind of the service document element, optional for entityset's must for FunctionImport and Singleton.</param> private void WriteServiceDocumentElement(ODataServiceDocumentElement serviceDocumentElement, string kind) { // validate that the resource has a non-null url. ValidationUtils.ValidateServiceDocumentElement(serviceDocumentElement, ODataFormat.Json); // "{" this.JsonWriter.StartObjectScope(); // "name": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementName); this.JsonWriter.WriteValue(serviceDocumentElement.Name); // Do not write title if it is null or empty, or if title is the same as name. if (!string.IsNullOrEmpty(serviceDocumentElement.Title) && !serviceDocumentElement.Title.Equals(serviceDocumentElement.Name, StringComparison.Ordinal)) { // "title": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementTitle); this.JsonWriter.WriteValue(serviceDocumentElement.Title); } // Not always writing because it can be null if an ODataEntitySetInfo, not necessary to write this. Required for the others though. if (kind != null) { // "kind": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementKind); this.JsonWriter.WriteValue(kind); } // "url": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementUrlName); this.JsonWriter.WriteValue(this.UriToString(serviceDocumentElement.Url)); // "}" this.JsonWriter.EndObjectScope(); }
/// <summary> /// Creates a <see cref="ODataServiceDocumentElement"/>. /// </summary> /// <param name="kind">Property values for the "kind" property.</param> /// <returns>A <see cref="ODataServiceDocumentElement"/> instance.</returns> private static ODataServiceDocumentElement CreateServiceDocumentElement(string[] kind) { // If not specified its an entity set. if (kind[0] == null) { return(new ODataEntitySetInfo()); } ODataServiceDocumentElement serviceDocumentElement = null; if (kind[0].Equals(JsonLightConstants.ServiceDocumentEntitySetKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataEntitySetInfo(); } else if (kind[0].Equals(JsonLightConstants.ServiceDocumentFunctionImportKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataFunctionImportInfo(); } else if (kind[0].Equals(JsonLightConstants.ServiceDocumentSingletonKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataSingletonInfo(); } return(serviceDocumentElement); }
/// <summary> /// Writes a service document element in service document. /// </summary> /// <param name="serviceDocumentElement">The serviceDocument element resource to write.</param> /// <param name="elementName">The element name of the service document element to write.</param> private void WriteNonEntitySetInfoElement(ODataServiceDocumentElement serviceDocumentElement, string elementName) { // validate that the resource has a non-null url. #pragma warning disable 618 ValidationUtils.ValidateServiceDocumentElement(serviceDocumentElement, ODataFormat.Atom); #pragma warning restore 618 // <metadata:elementName> this.XmlWriter.WriteStartElement(AtomConstants.ODataMetadataNamespacePrefix, elementName, AtomConstants.ODataMetadataNamespace); // The name of the elementName is the resource name; The href of the <m:elementName> element must be the link for the elementName. // Since we model the collection as having a 'Name' (for JSON) we require a base Uri for Atom/Xml. this.XmlWriter.WriteAttributeString(AtomConstants.AtomHRefAttributeName, this.UriToUrlAttributeValue(serviceDocumentElement.Url)); // TODO: According to the V4 spec we might want to omit writing this if the Url is the same as the Name, writing it always for now. this.atomServiceDocumentMetadataSerializer.WriteTextConstruct(AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, serviceDocumentElement.Name); // </metadata:elementName> this.XmlWriter.WriteEndElement(); }
/// <summary> /// Reads a resource collection within a service document. /// </summary> /// <param name="propertyAndAnnotationCollector">The <see cref="PropertyAndAnnotationCollector"/> to use for parsing annotations within the service document element object.</param> /// <returns>A <see cref="ODataEntitySetInfo"/> representing the read resource collection.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.StartObject: The beginning of the JSON object representing the service document element. /// 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 service document element. (Would be invalid). /// </remarks> private ODataServiceDocumentElement ReadServiceDocumentElement(PropertyAndAnnotationCollector propertyAndAnnotationCollector) { this.JsonReader.ReadStartObject(); string[] name = { null }; string[] url = { null }; string[] kind = { null }; string[] title = { null }; while (this.JsonReader.NodeType == JsonNodeType.Property) { // OData property annotations are not supported in service document element objects. Func <string, object> propertyAnnotationValueReader = annotationName => { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationInServiceDocumentElement(annotationName)); }; this.ProcessProperty( propertyAndAnnotationCollector, propertyAnnotationValueReader, (propertyParsingResult, propertyName) => { if (this.JsonReader.NodeType == JsonNodeType.Property) { // Read over property name this.JsonReader.Read(); } switch (propertyParsingResult) { case PropertyParsingResult.ODataInstanceAnnotation: throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_InstanceAnnotationInServiceDocumentElement(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.ODataServiceDocumentElementName, propertyName) == 0) { if (name[0] != null) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementName)); } name[0] = this.JsonReader.ReadStringValue(); } else if (string.CompareOrdinal(JsonLightConstants.ODataServiceDocumentElementUrlName, propertyName) == 0) { if (url[0] != null) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementUrlName)); } url[0] = this.JsonReader.ReadStringValue(); ValidationUtils.ValidateServiceDocumentElementUrl(url[0]); } else if (string.CompareOrdinal(JsonLightConstants.ODataServiceDocumentElementKind, propertyName) == 0) { if (kind[0] != null) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementKind)); } kind[0] = this.JsonReader.ReadStringValue(); } else if (string.CompareOrdinal(JsonLightConstants.ODataServiceDocumentElementTitle, propertyName) == 0) { if (title[0] != null) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementTitle)); } title[0] = this.JsonReader.ReadStringValue(); } else { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_UnexpectedPropertyInServiceDocumentElement(propertyName, JsonLightConstants.ODataServiceDocumentElementName, JsonLightConstants.ODataServiceDocumentElementUrlName)); } break; } }); } // URL and Name are mandatory if (string.IsNullOrEmpty(name[0])) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_MissingRequiredPropertyInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementName)); } if (string.IsNullOrEmpty(url[0])) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_MissingRequiredPropertyInServiceDocumentElement(JsonLightConstants.ODataServiceDocumentElementUrlName)); } ODataServiceDocumentElement serviceDocumentElement = null; if (kind[0] != null) { if (kind[0].Equals(JsonLightConstants.ServiceDocumentEntitySetKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataEntitySetInfo(); } else if (kind[0].Equals(JsonLightConstants.ServiceDocumentFunctionImportKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataFunctionImportInfo(); } else if (kind[0].Equals(JsonLightConstants.ServiceDocumentSingletonKindName, StringComparison.Ordinal)) { serviceDocumentElement = new ODataSingletonInfo(); } } else { // if not specified its an entity set. serviceDocumentElement = new ODataEntitySetInfo(); } if (serviceDocumentElement != null) { serviceDocumentElement.Url = this.ProcessUriFromPayload(url[0]); serviceDocumentElement.Name = name[0]; serviceDocumentElement.Title = title[0]; } this.JsonReader.ReadEndObject(); return(serviceDocumentElement); }
/// <summary> /// Read a service document. /// This method reads the service document from the input and returns /// an <see cref="ODataServiceDocument"/> that represents the read service document. /// </summary> /// <param name="propertyAndAnnotationCollector">The duplicate property names checker to use for the top-level scope.</param> /// <returns>An <see cref="ODataServiceDocument"/> representing the read service document.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.Property The property right after the context URI property. /// JsonNodeType.EndObject The EndObject of the service document. /// Post-Condition: Any The node after the EndObject of the service document. /// </remarks> private ODataServiceDocument ReadServiceDocumentImplementation(PropertyAndAnnotationCollector propertyAndAnnotationCollector) { Debug.Assert(propertyAndAnnotationCollector != null, "propertyAndAnnotationCollector != null"); this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); List <ODataServiceDocumentElement>[] serviceDocumentElements = { 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( propertyAndAnnotationCollector, readPropertyAnnotationInServiceDoc, (propertyParsingResult, propertyName) => { if (this.JsonReader.NodeType == JsonNodeType.Property) { // Read over property name this.JsonReader.Read(); } 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 (serviceDocumentElements[0] != null) { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_DuplicatePropertiesInServiceDocument(JsonLightConstants.ODataValuePropertyName)); } serviceDocumentElements[0] = new List <ODataServiceDocumentElement>(); // Read the value of the 'value' property. this.JsonReader.ReadStartArray(); PropertyAndAnnotationCollector resourceCollectionPropertyAndAnnotationCollector = this.CreatePropertyAndAnnotationCollector(); while (this.JsonReader.NodeType != JsonNodeType.EndArray) { ODataServiceDocumentElement serviceDocumentElement = this.ReadServiceDocumentElement(resourceCollectionPropertyAndAnnotationCollector); if (serviceDocumentElement != null) { serviceDocumentElements[0].Add(serviceDocumentElement); } resourceCollectionPropertyAndAnnotationCollector.Reset(); } 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 (serviceDocumentElements[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 ODataServiceDocument { EntitySets = new ReadOnlyEnumerable <ODataEntitySetInfo>(serviceDocumentElements[0].OfType <ODataEntitySetInfo>().ToList()), FunctionImports = new ReadOnlyEnumerable <ODataFunctionImportInfo>(serviceDocumentElements[0].OfType <ODataFunctionImportInfo>().ToList()), Singletons = new ReadOnlyEnumerable <ODataSingletonInfo>(serviceDocumentElements[0].OfType <ODataSingletonInfo>().ToList()) }); }
/// <summary> /// Reads an atom:title element and adds the new information to <paramref name="odataServiceDocumentElement"/> 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="odataServiceDocumentElement">The non-null service document element 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, ODataServiceDocumentElement odataServiceDocumentElement) { Debug.Assert(!this.ReadAtomMetadata || collectionMetadata != null, "collectionMetadata parameter should be non-null when ATOM metadata reading is enabled."); Debug.Assert(odataServiceDocumentElement != 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."); AtomTextConstruct titleTextConstruct = this.ReadTitleElement(); if (odataServiceDocumentElement.Name == null) { odataServiceDocumentElement.Name = titleTextConstruct.Text; } if (this.ReadAtomMetadata) { collectionMetadata.Title = titleTextConstruct; } }
/// <summary> /// Writes a element (EntitySet, Singleton or FunctionImport) in service document. /// </summary> /// <param name="serviceDocumentElement">The element in service document to write.</param> /// <param name="kind">Kind of the service document element, optional for entityset's must for FunctionImport and Singleton.</param> private void WriteServiceDocumentElement(ODataServiceDocumentElement serviceDocumentElement, string kind) { // validate that the resource has a non-null url. this.WriterValidator.ValidateServiceDocumentElement(serviceDocumentElement, ODataFormat.Json); // "{" this.JsonWriter.StartObjectScope(); // "name": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementName); this.JsonWriter.WriteValue(serviceDocumentElement.Name); // Do not write title if it is null or empty, or if title is the same as name. if (!string.IsNullOrEmpty(serviceDocumentElement.Title) && !serviceDocumentElement.Title.Equals(serviceDocumentElement.Name, StringComparison.Ordinal)) { // "title": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementTitle); this.JsonWriter.WriteValue(serviceDocumentElement.Title); } // Not always writing because it can be null if an ODataEntitySetInfo, not necessary to write this. Required for the others though. if (kind != null) { // "kind": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementKind); this.JsonWriter.WriteValue(kind); } // "url": ... this.JsonWriter.WriteName(JsonLightConstants.ODataServiceDocumentElementUrlName); this.JsonWriter.WriteValue(this.UriToString(serviceDocumentElement.Url)); // "}" this.JsonWriter.EndObjectScope(); }
/// <summary> /// Asynchronously reads a resource collection within a service document. /// </summary> /// <param name="propertyAndAnnotationCollector"> /// The <see cref="PropertyAndAnnotationCollector"/> to use for parsing annotations within the service document element object. /// </param> /// <returns> /// A task that represents the asynchronous read operation. /// The value of the TResult parameter contains an <see cref="ODataEntitySetInfo"/> representing the read resource collection. /// </returns> /// <remarks> /// Pre-Condition: JsonNodeType.StartObject: The beginning of the JSON object representing the service document element. /// 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 service document element. (Would be invalid). /// </remarks> private async Task <ODataServiceDocumentElement> ReadServiceDocumentElementAsync(PropertyAndAnnotationCollector propertyAndAnnotationCollector) { await this.JsonReader.ReadStartObjectAsync() .ConfigureAwait(false); string[] name = { null }; string[] url = { null }; string[] kind = { null }; string[] title = { null }; while (this.JsonReader.NodeType == JsonNodeType.Property) { // OData property annotations are not supported in service document element objects. Func <string, Task <object> > propertyAnnotationValueReaderAsync = annotationName => { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_PropertyAnnotationInServiceDocumentElement(annotationName)); }; await this.ProcessPropertyAsync( propertyAndAnnotationCollector, propertyAnnotationValueReaderAsync, async (propertyParsingResult, propertyName) => { if (this.JsonReader.NodeType == JsonNodeType.Property) { // Read over property name await this.JsonReader.ReadAsync() .ConfigureAwait(false); } switch (propertyParsingResult) { case PropertyParsingResult.ODataInstanceAnnotation: throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_InstanceAnnotationInServiceDocumentElement(propertyName)); case PropertyParsingResult.CustomInstanceAnnotation: await this.JsonReader.SkipValueAsync() .ConfigureAwait(false); 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.Equals(JsonLightConstants.ODataServiceDocumentElementName, propertyName, StringComparison.Ordinal)) { ValidateServiceDocumentElementHasNoRepeatedProperty(JsonLightConstants.ODataServiceDocumentElementName, name); name[0] = await this.JsonReader.ReadStringValueAsync() .ConfigureAwait(false); } else if (string.Equals(JsonLightConstants.ODataServiceDocumentElementUrlName, propertyName, StringComparison.Ordinal)) { ValidateServiceDocumentElementHasNoRepeatedProperty(JsonLightConstants.ODataServiceDocumentElementUrlName, url); url[0] = await this.JsonReader.ReadStringValueAsync() .ConfigureAwait(false); ValidationUtils.ValidateServiceDocumentElementUrl(url[0]); } else if (string.Equals(JsonLightConstants.ODataServiceDocumentElementKind, propertyName, StringComparison.Ordinal)) { ValidateServiceDocumentElementHasNoRepeatedProperty(JsonLightConstants.ODataServiceDocumentElementKind, kind); kind[0] = await this.JsonReader.ReadStringValueAsync() .ConfigureAwait(false); } else if (string.Equals(JsonLightConstants.ODataServiceDocumentElementTitle, propertyName, StringComparison.Ordinal)) { ValidateServiceDocumentElementHasNoRepeatedProperty(JsonLightConstants.ODataServiceDocumentElementTitle, title); title[0] = await this.JsonReader.ReadStringValueAsync() .ConfigureAwait(false); } else { throw new ODataException(Strings.ODataJsonLightServiceDocumentDeserializer_UnexpectedPropertyInServiceDocumentElement( propertyName, JsonLightConstants.ODataServiceDocumentElementName, JsonLightConstants.ODataServiceDocumentElementUrlName)); } break; } }).ConfigureAwait(false); } // URL and Name are mandatory ValidateServiceDocumentElementHasRequiredProperty(JsonLightConstants.ODataServiceDocumentElementName, name); ValidateServiceDocumentElementHasRequiredProperty(JsonLightConstants.ODataServiceDocumentElementUrlName, url); ODataServiceDocumentElement serviceDocumentElement = CreateServiceDocumentElement(kind); if (serviceDocumentElement != null) { serviceDocumentElement.Url = this.ProcessUriFromPayload(url[0]); serviceDocumentElement.Name = name[0]; serviceDocumentElement.Title = title[0]; } await this.JsonReader.ReadEndObjectAsync() .ConfigureAwait(false); return(serviceDocumentElement); }
/// <summary> /// Writes a service document element in service document. /// </summary> /// <param name="serviceDocumentElement">The serviceDocument element resource to write.</param> /// <param name="elementName">The element name of the service document element to write.</param> private void WriteNonEntitySetInfoElement(ODataServiceDocumentElement serviceDocumentElement, string elementName) { // validate that the resource has a non-null url. #pragma warning disable 618 ValidationUtils.ValidateServiceDocumentElement(serviceDocumentElement, ODataFormat.Atom); #pragma warning restore 618 // <metadata:elementName> this.XmlWriter.WriteStartElement(AtomConstants.ODataMetadataNamespacePrefix, elementName, AtomConstants.ODataMetadataNamespace); // The name of the elementName is the resource name; The href of the <m:elementName> element must be the link for the elementName. // Since we model the collection as having a 'Name' (for JSON) we require a base Uri for Atom/Xml. this.XmlWriter.WriteAttributeString(AtomConstants.AtomHRefAttributeName, this.UriToUrlAttributeValue(serviceDocumentElement.Url)); // TODO: According to the V4 spec we might want to omit writing this if the Url is the same as the Name, writing it always for now. this.atomServiceDocumentMetadataSerializer.WriteTextConstruct(AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, serviceDocumentElement.Name); // </metadata:elementName> this.XmlWriter.WriteEndElement(); }
/// <summary> /// Reads an atom:title element and adds the new information to <paramref name="odataServiceDocumentElement"/> 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="odataServiceDocumentElement">The non-null service document element 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, ODataServiceDocumentElement odataServiceDocumentElement) { Debug.Assert(!this.ReadAtomMetadata || collectionMetadata != null, "collectionMetadata parameter should be non-null when ATOM metadata reading is enabled."); Debug.Assert(odataServiceDocumentElement != 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."); AtomTextConstruct titleTextConstruct = this.ReadTitleElement(); if (odataServiceDocumentElement.Name == null) { odataServiceDocumentElement.Name = titleTextConstruct.Text; } if (this.ReadAtomMetadata) { collectionMetadata.Title = titleTextConstruct; } }