Ejemplo n.º 1
0
        /// <summary>
        /// If <paramref name="annotationName"/> is under the odata namespace but is not known to ODataLib, move the JSON reader forward to skip the
        /// annotation name and value then return true; return false otherwise.
        /// </summary>
        /// <remarks>
        /// The unknown odata annotation is skipped so that when this version of the reader reads a resource set produced by a future version of ODataLib
        /// that contains an odata annotation that is not recognized on this version, we would simply ignore the annotation rather than failing.
        /// Note that when we add new odata annotations that cannot be skipped, we would bump the protocol version.
        /// </remarks>
        /// <param name="annotationName">The annotation name in question.</param>
        /// <param name="annotationValue">Outputs the .</param>
        /// <returns>Returns true if the annotation name and value is skipped; returns false otherwise.</returns>
        private bool SkippedOverUnknownODataAnnotation(string annotationName, out object annotationValue)
        {
            Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)");
            this.AssertJsonCondition(JsonNodeType.Property);

            if (ODataAnnotationNames.IsUnknownODataAnnotationName(annotationName))
            {
                annotationValue = ReadODataOrCustomInstanceAnnotationValue(annotationName);
                return(true);
            }

            annotationValue = null;
            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Asynchronously read an entity reference link.
        /// </summary>
        /// <param name="propertyAndAnnotationCollector">The duplicate property names checker to check for duplicate properties and
        /// duplicate annotations; this is a separate instance per entity reference link.</param>
        /// <param name="topLevel">true if we are reading a singleton entity reference link at the top level; false if we are reading
        /// an entity reference link as part of a collection of entity reference links.</param>
        /// <returns>
        /// A task that represents the asynchronous read operation.
        /// The value of the TResult parameter contains an instance of <see cref="ODataEntityReferenceLink"/> which was read.
        /// </returns>
        /// <remarks>
        /// Pre-Condition:  StartObject     when the entity reference link is part of a collection
        ///                 Property        the first property in the entity reference link (for a top-level link)
        ///                 EndObject       the end object node of an entity reference link (for a top-level link)
        /// Post-Condition: EndInput        for a top-level object
        ///                 EndArray        for the last link in a collection of links
        ///                 Any             for the first node of the next link in a collection of links
        /// </remarks>
        private async Task <ODataEntityReferenceLink> ReadSingleEntityReferenceLinkAsync(PropertyAndAnnotationCollector propertyAndAnnotationCollector, bool topLevel)
        {
            this.JsonReader.AssertNotBuffering();

            if (!topLevel)
            {
                if (this.JsonReader.NodeType != JsonNodeType.StartObject)
                {
                    // entity reference link has to be an object
                    throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_EntityReferenceLinkMustBeObjectValue(this.JsonReader.NodeType));
                }

                await this.JsonReader.ReadStartObjectAsync()
                .ConfigureAwait(false);
            }

            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

            ODataEntityReferenceLink[] entityReferenceLink = { null };

            // Entity  reference links use instance annotations. Fail if we find a  property annotation.
            Func <string, Task <object> > propertyAnnotationValueReaderDelegate =
                annotationName =>
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLink(annotationName));
            };

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                this.ReadPropertyCustomAnnotationValueAsync = this.ReadCustomInstanceAnnotationValueAsync;
                await this.ProcessPropertyAsync(
                    propertyAndAnnotationCollector,
                    propertyAnnotationValueReaderDelegate,
                    async (propertyParsingResult, propertyName) =>
                {
                    if (this.JsonReader.NodeType == JsonNodeType.Property)
                    {
                        // Read over property name
                        await this.JsonReader.ReadAsync()
                        .ConfigureAwait(false);
                    }

                    switch (propertyParsingResult)
                    {
                    case PropertyParsingResult.ODataInstanceAnnotation:
                        if (!string.Equals(ODataAnnotationNames.ODataId, propertyName, StringComparison.Ordinal))
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyInEntityReferenceLink(propertyName, ODataAnnotationNames.ODataId));
                        }
                        else if (entityReferenceLink[0] != null)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_MultipleUriPropertiesInEntityReferenceLink(ODataAnnotationNames.ODataId));
                        }

                        // read the value of the 'odata.id' annotation
                        string urlString = await this.JsonReader.ReadStringValueAsync(ODataAnnotationNames.ODataId)
                                           .ConfigureAwait(false);
                        if (urlString == null)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_EntityReferenceLinkUrlCannotBeNull(ODataAnnotationNames.ODataId));
                        }

                        entityReferenceLink[0] = new ODataEntityReferenceLink
                        {
                            Url = this.ProcessUriFromPayload(urlString)
                        };

                        ReaderValidationUtils.ValidateEntityReferenceLink(entityReferenceLink[0]);

                        break;

                    case PropertyParsingResult.CustomInstanceAnnotation:
                        if (entityReferenceLink[0] == null)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_MissingEntityReferenceLinkProperty(ODataAnnotationNames.ODataId));
                        }

                        Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");
                        this.AssertJsonCondition(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, JsonNodeType.StartArray);
                        ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName);
                        Debug.Assert(
                            !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName),
                            "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(propertyName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                        object annotationValue = await this.ReadCustomInstanceAnnotationValueAsync(propertyAndAnnotationCollector, propertyName)
                                                 .ConfigureAwait(false);
                        entityReferenceLink[0].InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, annotationValue.ToODataValue()));
                        break;

                    case PropertyParsingResult.PropertyWithValue:
                    case PropertyParsingResult.PropertyWithoutValue:
                        // entity reference link  is denoted by odata.id annotation
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidAnnotationInEntityReferenceLink(propertyName));

                    case PropertyParsingResult.EndOfObject:
                        break;

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

                    default:
                        throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadSingleEntityReferenceLink));
                    }
                }).ConfigureAwait(false);
            }

            if (entityReferenceLink[0] == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_MissingEntityReferenceLinkProperty(ODataAnnotationNames.ODataId));
            }

            // end of the entity reference link object
            await this.JsonReader.ReadEndObjectAsync()
            .ConfigureAwait(false);

            this.JsonReader.AssertNotBuffering();
            return(entityReferenceLink[0]);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Asynchronously reads the entity reference link instance annotations.
        /// </summary>
        /// <param name="links">The <see cref="ODataEntityReferenceLinks"/> to read the annotations for.</param>
        /// <param name="propertyAndAnnotationCollector">The duplicate property names checker for the entity reference links scope.</param>
        /// <param name="forLinksStart">true when parsing the instance annotations before the 'value' property;
        /// false when parsing the instance annotations after the 'value' property.</param>
        /// <returns>A task that represents the asynchronous read operation.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.Property               The first property in the payload (or the first property after the context URI in responses)
        ///                 JsonNodeType.EndObject              The end of the entity reference links object
        /// Post-Condition: JsonNodeType.EndObject              When the end of the entity reference links object is reached
        ///                 Any                                 The first node of the value of the 'url' property (if found)
        /// </remarks>
        private async Task ReadEntityReferenceLinksAnnotationsAsync(
            ODataEntityReferenceLinks links,
            PropertyAndAnnotationCollector propertyAndAnnotationCollector,
            bool forLinksStart)
        {
            Debug.Assert(links != null, "links != null");
            Debug.Assert(propertyAndAnnotationCollector != null, "propertyAndAnnotationCollector != null");
            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
            this.JsonReader.AssertNotBuffering();

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                // OData property annotations are not supported on entity reference links.
                Func <string, Task <object> > propertyAnnotationValueReaderDelegate =
                    annotationName =>
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLinks);
                };

                bool foundValueProperty = false;
                this.ReadPropertyCustomAnnotationValueAsync = this.ReadCustomInstanceAnnotationValueAsync;
                await this.ProcessPropertyAsync(
                    propertyAndAnnotationCollector,
                    propertyAnnotationValueReaderDelegate,
                    async (propertyParseResult, propertyName) =>
                {
                    if (this.JsonReader.NodeType == JsonNodeType.Property)
                    {
                        // Read over property name
                        await this.JsonReader.ReadAsync()
                        .ConfigureAwait(false);
                    }

                    switch (propertyParseResult)
                    {
                    case PropertyParsingResult.ODataInstanceAnnotation:
                        if (string.Equals(ODataAnnotationNames.ODataNextLink, propertyName, StringComparison.Ordinal))
                        {
                            this.AssertJsonCondition(JsonNodeType.PrimitiveValue);
                            Uri nextPageUri = await this.ReadAndValidateAnnotationStringValueAsUriAsync(ODataAnnotationNames.ODataNextLink)
                                              .ConfigureAwait(false);
                            Debug.Assert(links.NextPageLink == null, "We should have checked for duplicates already.");
                            links.NextPageLink = nextPageUri;
                        }
                        else if (string.Equals(ODataAnnotationNames.ODataCount, propertyName, StringComparison.Ordinal))
                        {
                            this.AssertJsonCondition(JsonNodeType.PrimitiveValue);
                            Debug.Assert(!links.Count.HasValue, "We should have checked for duplicates already.");
                            links.Count = await this.ReadAndValidateAnnotationAsLongForIeee754CompatibleAsync(ODataAnnotationNames.ODataCount)
                                          .ConfigureAwait(false);
                        }
                        else
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName));
                        }

                        break;

                    case PropertyParsingResult.CustomInstanceAnnotation:
                        Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");
                        this.AssertJsonCondition(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, JsonNodeType.StartArray);
                        ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName);
                        Debug.Assert(
                            !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName),
                            "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(propertyName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                        object annotationValue = await this.ReadCustomInstanceAnnotationValueAsync(propertyAndAnnotationCollector, propertyName)
                                                 .ConfigureAwait(false);
                        links.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, annotationValue.ToODataValue()));
                        break;

                    case PropertyParsingResult.PropertyWithValue:
                        if (!string.Equals(JsonLightConstants.ODataValuePropertyName, propertyName, StringComparison.Ordinal))
                        {
                            // We did not find a supported link collection property; fail.
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidEntityReferenceLinksPropertyFound(propertyName, JsonLightConstants.ODataValuePropertyName));
                        }

                        // We found the link collection property and are done parsing property annotations;
                        foundValueProperty = true;
                        break;

                    case PropertyParsingResult.PropertyWithoutValue:
                        // If we find a property without a value it means that we did not find the entity reference links property (yet)
                        // but an invalid property annotation
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyAnnotationInEntityReferenceLinks(propertyName));

                    case PropertyParsingResult.EndOfObject:
                        break;

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

                    default:
                        throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadEntityReferenceLinksAnnotations));
                    }
                }).ConfigureAwait(false);

                if (foundValueProperty)
                {
                    return;
                }
            }

            if (forLinksStart)
            {
                // We did not find the 'value' property.
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksPropertyNotFound(JsonLightConstants.ODataValuePropertyName));
            }

            this.AssertJsonCondition(JsonNodeType.EndObject);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Reads the entity reference link instance annotations.
        /// </summary>
        /// <param name="links">The <see cref="ODataEntityReferenceLinks"/> to read the annotations for.</param>
        /// <param name="propertyAndAnnotationCollector">The duplicate property names checker for the entity reference links scope.</param>
        /// <param name="forLinksStart">true when parsing the instance annotations before the 'value' property;
        /// false when parsing the instance annotations after the 'value' property.</param>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.Property               The first property in the payload (or the first property after the context URI in responses)
        ///                 JsonNodeType.EndObject              The end of the entity reference links object
        /// Post-Condition: JsonNodeType.EndObject              When the end of the entity reference links object is reached
        ///                 Any                                 The first node of the value of the 'url' property (if found)
        /// </remarks>
        private void ReadEntityReferenceLinksAnnotations(ODataEntityReferenceLinks links, PropertyAndAnnotationCollector propertyAndAnnotationCollector, bool forLinksStart)
        {
            Debug.Assert(links != null, "links != null");
            Debug.Assert(propertyAndAnnotationCollector != null, "propertyAndAnnotationCollector != null");
            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
            this.JsonReader.AssertNotBuffering();

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                // OData property annotations are not supported on entity reference links.
                Func <string, object> propertyAnnotationValueReader =
                    annotationName => { throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLinks); };

                bool foundValueProperty = false;
                this.ProcessProperty(
                    propertyAndAnnotationCollector,
                    propertyAnnotationValueReader,
                    (propertyParseResult, propertyName) =>
                {
                    if (this.JsonReader.NodeType == JsonNodeType.Property)
                    {
                        // Read over property name
                        this.JsonReader.Read();
                    }

                    switch (propertyParseResult)
                    {
                    case PropertyParsingResult.ODataInstanceAnnotation:
                        if (string.CompareOrdinal(ODataAnnotationNames.ODataNextLink, propertyName) == 0)
                        {
                            this.ReadEntityReferenceLinksNextLinkAnnotationValue(links);
                        }
                        else if (string.CompareOrdinal(ODataAnnotationNames.ODataCount, propertyName) == 0)
                        {
                            this.ReadEntityReferenceCountAnnotationValue(links);
                        }
                        else
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName));
                        }

                        break;

                    case PropertyParsingResult.CustomInstanceAnnotation:
                        Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");
                        this.AssertJsonCondition(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, JsonNodeType.StartArray);
                        ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName);
                        Debug.Assert(
                            !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName),
                            "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(propertyName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                        object annotationValue = this.ReadCustomInstanceAnnotationValue(propertyAndAnnotationCollector, propertyName);
                        links.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, annotationValue.ToODataValue()));
                        break;

                    case PropertyParsingResult.PropertyWithValue:
                        if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) != 0)
                        {
                            // We did not find a supported link collection property; fail.
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidEntityReferenceLinksPropertyFound(propertyName, JsonLightConstants.ODataValuePropertyName));
                        }

                        // We found the link collection property and are done parsing property annotations;
                        foundValueProperty = true;
                        break;

                    case PropertyParsingResult.PropertyWithoutValue:
                        // If we find a property without a value it means that we did not find the entity reference links property (yet)
                        // but an invalid property annotation
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyAnnotationInEntityReferenceLinks(propertyName));

                    case PropertyParsingResult.EndOfObject:
                        break;

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

                    default:
                        throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadEntityReferenceLinksAnnotations));
                    }
                });

                if (foundValueProperty)
                {
                    return;
                }
            }

            if (forLinksStart)
            {
                // We did not find the 'value' property.
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksPropertyNotFound(JsonLightConstants.ODataValuePropertyName));
            }

            this.AssertJsonCondition(JsonNodeType.EndObject);
        }