/// <summary> /// This method creates and reads the property from the input and /// returns an <see cref="ODataProperty"/> representing the read property. /// </summary> /// <param name="expectedProperty">The <see cref="IEdmProperty"/> producing the property to be read.</param> /// <param name="expectedPropertyTypeReference">The expected type of the property to read.</param> /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns> internal ODataProperty ReadTopLevelProperty(IEdmStructuralProperty expectedProperty, IEdmTypeReference expectedPropertyTypeReference) { Debug.Assert( expectedPropertyTypeReference == null || !expectedPropertyTypeReference.IsODataEntityTypeKind(), "If the expected type is specified it must not be an entity type."); Debug.Assert(this.XmlReader != null, "this.xmlReader != null"); this.ReadPayloadStart(); Debug.Assert(this.XmlReader.NodeType == XmlNodeType.Element, "The XML reader must be positioned on an Element."); // For compatibility with WCF DS Server we need to be able to read the property element in any namespace, not just the OData namespace. if (!this.UseServerFormatBehavior && !this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace)) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_TopLevelPropertyElementWrongNamespace(this.XmlReader.NamespaceURI, this.XmlReader.ODataMetadataNamespace)); } // this is a top level property so EPM does not apply hence it is safe to say that EPM is not present this.AssertRecursionDepthIsZero(); string expectedPropertyName = ReaderUtils.GetExpectedPropertyName(expectedProperty); ODataProperty property = this.ReadProperty( true, expectedPropertyName, expectedPropertyTypeReference, /*nullValueReadBehaviorKind*/ ODataNullValueBehaviorKind.Default); this.AssertRecursionDepthIsZero(); Debug.Assert(property != null, "If we don't ignore null values the property must not be null."); this.ReadPayloadEnd(); return(property); }
/// <summary> /// This method creates an reads the property from the input and /// returns an <see cref="ODataProperty"/> representing the read property. /// </summary> /// <param name="expectedProperty">The <see cref="IEdmProperty"/> producing the property to be read.</param> /// <param name="expectedPropertyTypeReference">The expected type reference of the property to read.</param> /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns> internal ODataProperty ReadTopLevelProperty(IEdmStructuralProperty expectedProperty, IEdmTypeReference expectedPropertyTypeReference) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet."); Debug.Assert( expectedPropertyTypeReference == null || !expectedPropertyTypeReference.IsODataEntityTypeKind(), "If the expected type is specified it must not be an entity type."); this.JsonReader.AssertNotBuffering(); if (!this.Model.IsUserModel()) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_TopLevelPropertyWithoutMetadata); } // Read the response wrapper "d" if expected. this.ReadPayloadStart(false /*isReadingNestedPayload*/); string expectedPropertyName = ReaderUtils.GetExpectedPropertyName(expectedProperty); string propertyName = null; object propertyValue = null; // We have to support reading top-level complex values without the { "property": ... } wrapper for open properties // in WCF DS Server backward compat mode. (Open property == property without expected type for us). if (this.ShouldReadTopLevelPropertyValueWithoutPropertyWrapper(expectedPropertyTypeReference)) { // We will report the value without property wrapper as a property with empty name (this is technically invalid, but it will only happen in WCF DS Server mode). propertyName = expectedPropertyName ?? string.Empty; // Read the value directly propertyValue = this.ReadNonEntityValue( expectedPropertyTypeReference, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, /*validateNullValue*/ true, propertyName); } else { // Read the start of the object container around the property { "property": ... } this.JsonReader.ReadStartObject(); // Read through all top-level properties, ignore the ones with reserved names (i.e., reserved // characters in their name) and throw if we find none or more than one properties without reserved name. bool foundProperty = false; string foundPropertyName = null; while (this.JsonReader.NodeType == JsonNodeType.Property) { // Read once - this should be the property propertyName = this.JsonReader.ReadPropertyName(); if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { if (foundProperty) { // There should be only one property in the top-level property wrapper that does not have a reserved name. throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidTopLevelPropertyPayload); } foundProperty = true; foundPropertyName = propertyName; // Now read the property value propertyValue = this.ReadNonEntityValue( expectedPropertyTypeReference, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, /*validateNullValue*/ true, propertyName); } } if (!foundProperty) { // No property found; there should be exactly one property in the top-level property wrapper that does not have a reserved name. throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidTopLevelPropertyPayload); } Debug.Assert(foundPropertyName != null, "foundPropertyName != null"); ReaderValidationUtils.ValidateExpectedPropertyName(expectedPropertyName, foundPropertyName); propertyName = foundPropertyName; // Read over the end object - note that this might be the last node in the input (in case there's no response wrapper) this.JsonReader.Read(); } // Read the end of the response wrapper "d" if expected. this.ReadPayloadEnd(false /*isReadingNestedPayload*/); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput"); this.JsonReader.AssertNotBuffering(); Debug.Assert(propertyName != null, "propertyName != null"); return(new ODataProperty { Name = propertyName, Value = propertyValue }); }