public void ReadInstanceAnnotationValueWillReadNullValueWithoutODataType()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.NullAnnotation\":null}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.NullAnnotation").Should().BeNull();
 }
 public void OnlyCustomAnnotationsForPropertyAddedShouldReturnNull()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation");
     duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation2");
     duplicateChecker.GetODataPropertyAnnotations("property").Should().BeNull();
 }
 public void DuplicatePropertyCustomAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.AddCustomPropertyAnnotation("property", "custom.name");
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed("custom.name", "property"));
 }
 public void DuplicatePropertyODataAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "name", null);
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(JsonLightConstants.ODataAnnotationNamespacePrefix + "name", "property"));
 }
 public void DuplicateInstanceCustomAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.MarkPropertyAsProcessed("custom.name");
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed("custom.name"));
 }
 public void AnnotationsForPropertyShouldBeStored()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "one", 1);
     duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "two", "Two");
     duplicateChecker.GetODataPropertyAnnotations("property").Should().Equal(new Dictionary<string, object>()
     {
         { JsonLightConstants.ODataAnnotationNamespacePrefix + "one", 1 },
         { JsonLightConstants.ODataAnnotationNamespacePrefix + "two", "Two" }
     });
 }
示例#7
0
        /// <summary>Checks that for duplicate association links and if there already is a navigation link with the same name
        /// sets the association link URL on that navigation link.</summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the current scope.</param>
        /// <param name="associationLinkName">The name of association link to be checked.</param>
        /// <param name="associationLinkUrl">The url of association link to be checked.</param>
        internal static void CheckForDuplicateAssociationLinkAndUpdateNavigationLink(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            string associationLinkName,
            Uri associationLinkUrl)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(associationLinkName != null, "associationLinkName != null");

            ODataNavigationLink navigationLink = duplicatePropertyNamesChecker.CheckForDuplicateAssociationLinkNames(associationLinkName, associationLinkUrl);

            // We must not set the AssociationLinkUrl to null since that would disable templating on it, but we want templating to work if the association link was not in the payload.
            if (navigationLink != null && navigationLink.AssociationLinkUrl == null && associationLinkUrl != null)
            {
                navigationLink.AssociationLinkUrl = associationLinkUrl;
            }
        }
示例#8
0
        /// <summary>Checks that for duplicate association links and if there already is a navigation link with the same name
        /// sets the association link URL on that navigation link.</summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the current scope.</param>
        /// <param name="associationLinkName">The name of association link to be checked.</param>
        /// <param name="associationLinkUrl">The url of association link to be checked.</param>
        internal static void CheckForDuplicateAssociationLinkAndUpdateNavigationLink(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            string associationLinkName,
            Uri associationLinkUrl)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(associationLinkName != null, "associationLinkName != null");

            ODataNavigationLink navigationLink = duplicatePropertyNamesChecker.CheckForDuplicateAssociationLinkNames(associationLinkName, associationLinkUrl);

            // We must not set the AssociationLinkUrl to null since that would disable templating on it, but we want templating to work if the association link was not in the payload.
            if (navigationLink != null && navigationLink.AssociationLinkUrl == null && associationLinkUrl != null)
            {
                navigationLink.AssociationLinkUrl = associationLinkUrl;
            }
        }
示例#9
0
        /// <summary>Checks for duplicate navigation links and if there already is an association link with the same name
        /// sets the association link URL on the navigation link.</summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the current scope.</param>
        /// <param name="navigationLink">The navigation link to be checked.</param>
        /// <param name="isExpanded">true if the link is expanded, false otherwise.</param>
        /// <param name="isCollection">true if the navigation link is a collection, false if it's a singleton or null if we don't know.</param>
        internal static void CheckForDuplicateNavigationLinkNameAndSetAssociationLink(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ODataNavigationLink navigationLink,
            bool isExpanded,
            bool?isCollection)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(navigationLink != null, "navigationLink != null");

            Uri associationLinkUrl = duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(navigationLink, isExpanded, isCollection);

            // We must not set the AssociationLinkUrl to null since that would disable templating on it, but we want templating to work if the association link was not in the payload.
            if (associationLinkUrl != null && navigationLink.AssociationLinkUrl == null)
            {
                navigationLink.AssociationLinkUrl = associationLinkUrl;
            }
        }
示例#10
0
        /// <summary>Checks for duplicate navigation links and if there already is an association link with the same name
        /// sets the association link URL on the navigation link.</summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the current scope.</param>
        /// <param name="navigationLink">The navigation link to be checked.</param>
        /// <param name="isExpanded">true if the link is expanded, false otherwise.</param>
        /// <param name="isCollection">true if the navigation link is a collection, false if it's a singleton or null if we don't know.</param>
        internal static void CheckForDuplicateNavigationLinkNameAndSetAssociationLink(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ODataNavigationLink navigationLink,
            bool isExpanded,
            bool? isCollection)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(navigationLink != null, "navigationLink != null");
            
            Uri associationLinkUrl = duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(navigationLink, isExpanded, isCollection);

            // We must not set the AssociationLinkUrl to null since that would disable templating on it, but we want templating to work if the association link was not in the payload.
            if (associationLinkUrl != null && navigationLink.AssociationLinkUrl == null)
            {
                navigationLink.AssociationLinkUrl = associationLinkUrl;
            }
        }
        /// <summary>
        /// Parses JSON object property starting with the current position of the JSON reader.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use, it will also store the property annotations found.</param>
        /// <param name="readPropertyAnnotationValue">Function called to read property annotation value.</param>
        /// <param name="handleProperty">Function callback to handle to resule of parse property.</param>
        internal void ProcessProperty(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            Func<string, object> readPropertyAnnotationValue,
            Action<PropertyParsingResult, string> handleProperty)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(readPropertyAnnotationValue != null, "readPropertyAnnotationValue != null");
            Debug.Assert(handleProperty != null, "handleProperty != null");
            this.AssertJsonCondition(JsonNodeType.Property);

            string propertyName;
            PropertyParsingResult propertyParsingResult = this.ParseProperty(duplicatePropertyNamesChecker, readPropertyAnnotationValue, out propertyName);

            while (propertyParsingResult == PropertyParsingResult.CustomInstanceAnnotation && this.ShouldSkipCustomInstanceAnnotation(propertyName))
            {
                // Make sure there's no duplicated instance annotation name even though we are skipping over it.
                duplicatePropertyNamesChecker.MarkPropertyAsProcessed(propertyName);

                // Skip over the instance annotation value and don't report it to the OM.
                this.JsonReader.SkipValue();

                propertyParsingResult = this.ParseProperty(duplicatePropertyNamesChecker, readPropertyAnnotationValue, out propertyName);
            }

            handleProperty(propertyParsingResult, propertyName);
            if (propertyParsingResult != PropertyParsingResult.EndOfObject)
            {
                duplicatePropertyNamesChecker.MarkPropertyAsProcessed(propertyName);
            }
        }
        /// <summary>
        /// Read the start of the top-level data wrapper in JSON responses.
        /// </summary>
        /// <param name="payloadKind">The kind of payload we are reading; this guides the parsing of the context URI.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param>
        /// <param name="isReadingNestedPayload">true if we are deserializing a nested payload, e.g. an entry, a feed or a collection within a parameters payload.</param>
        /// <param name="allowEmptyPayload">true if we allow a comletely empty payload; otherwise false.</param>
        /// <returns>The parsed context URI.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet when not reading a nested payload.
        /// Post-Condition: The reader is positioned on the first property of the payload after having read (or skipped) the context URI property.
        ///                 Or the reader is positioned on an end-object node if there are no properties (other than the context URI which is required in responses and optional in requests).
        /// </remarks>
        internal Task ReadPayloadStartAsync(
            ODataPayloadKind payloadKind,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            bool isReadingNestedPayload,
            bool allowEmptyPayload)
        {
            this.JsonReader.AssertNotBuffering();
            Debug.Assert(isReadingNestedPayload || this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: JSON reader must not have been used yet when not reading a nested payload.");

            return TaskUtils.GetTaskForSynchronousOperation(() =>
                {
                    string contextUriAnnotationValue = this.ReadPayloadStartImplementation(
                        payloadKind,
                        duplicatePropertyNamesChecker,
                        isReadingNestedPayload,
                        allowEmptyPayload);

                    // The context URI is only recognized in non-error response top-level payloads.
                    // If the payload is nested (for example when we read URL literals) we don't recognize the context URI.
                    // Top-level error payloads don't need and use the context URI.
                    if (!isReadingNestedPayload && payloadKind != ODataPayloadKind.Error && contextUriAnnotationValue != null)
                    {
                        this.contextUriParseResult = ODataJsonLightContextUriParser.Parse(
                            this.Model,
                            contextUriAnnotationValue,
                            payloadKind,
                            this.MessageReaderSettings.ReaderBehavior,
                            this.JsonLightInputContext.ReadingResponse);
                    }

#if DEBUG
                    this.contextUriParseResultReady = true;
#endif
                });
        }
 public void ReadInstanceAnnotationValueWhenODataTypeAnnotationIsMissingForCollectionValue()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@OData.CollectionAnnotation\":[]}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     object tmp = deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "OData.CollectionAnnotation");
     tmp.As<ODataCollectionValue>().Items.Cast<string>().Count().Should().Be(0);
     tmp.As<ODataCollectionValue>().TypeName.ShouldBeEquivalentTo(null);
 }
 public void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isTopLevel, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     this.WriteComplexVerifier.Should().NotBeNull("WriteComplexValue was called.");
     this.WriteComplexVerifier(complexValue, metadataTypeReference, isTopLevel, isOpenPropertyType, duplicatePropertyNamesChecker);
 }
        /// <summary>
        /// Process the current property annotation.
        /// </summary>
        /// <param name="annotatedPropertyName">The name being annotated. Can be a property or an instance annotation.</param>
        /// <param name="annotationName">The annotation targeting the <paramref name="annotatedPropertyName"/>.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param>
        /// <param name="readPropertyAnnotationValue">Callback to read the property annotation value.</param>
        private void ProcessPropertyAnnotation(string annotatedPropertyName, string annotationName, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func<string, object> readPropertyAnnotationValue)
        {
            // We don't currently support annotation targeting an instance annotation except for the @odata.type property annotation.
            if (ODataJsonLightReaderUtils.IsAnnotationProperty(annotatedPropertyName) && string.CompareOrdinal(annotationName, ODataAnnotationNames.ODataType) != 0)
            {
                throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_OnlyODataTypeAnnotationCanTargetInstanceAnnotation(annotationName, annotatedPropertyName, ODataAnnotationNames.ODataType));
            }

            // Read over the property name.
            this.JsonReader.Read();
            if (ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName))
            {
                // OData annotations are read.
                duplicatePropertyNamesChecker.AddODataPropertyAnnotation(annotatedPropertyName, annotationName, readPropertyAnnotationValue(annotationName));
            }
            else
            {
                if (this.ShouldSkipCustomInstanceAnnotation(annotationName) || (this is ODataJsonLightErrorDeserializer && this.MessageReaderSettings.ShouldIncludeAnnotation == null))
                {
                    // Make sure there's no duplicated instance annotation name even though we are skipping over it.
                    duplicatePropertyNamesChecker.AddCustomPropertyAnnotation(annotatedPropertyName, annotationName);
                    this.JsonReader.SkipValue();
                }
                else
                {
                    Debug.Assert(ReadPropertyCustomAnnotationValue != null, "readPropertyCustomAnnotationValue != null");
                    duplicatePropertyNamesChecker.AddCustomPropertyAnnotation(annotatedPropertyName, annotationName, ReadPropertyCustomAnnotationValue(duplicatePropertyNamesChecker, annotationName));
                }
            }
        }
 public void ReadAndApplyFeedInstanceAnnotationValueShouldSetInstanceAnnotationOnFeed()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.Int32Annotation\":123}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     ODataFeed feed = new ODataFeed();
     deserializer.ReadAndApplyFeedInstanceAnnotationValue("custom.Int32Annotation", feed, duplicatePropertyNamesChecker);
     Assert.AreEqual(1, feed.InstanceAnnotations.Count);
     TestUtils.AssertODataValueAreEqual(new ODataPrimitiveValue(123), feed.InstanceAnnotations.Single(ia => ia.Name == "custom.Int32Annotation").Value);
 }
 public void ReadAndApplyFeedInstanceAnnotationValueShouldSetDeltaLinkOnFeed()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.context\":\"http://host/$metadata#TestEntitySet\",\"@odata.deltaLink\":\"relativeUrl\"}");
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadPayloadStart(ODataPayloadKind.Feed, duplicatePropertyNamesChecker, false /*isReadingNestedPayload*/, false /*allowEmptyPayload*/);
     deserializer.JsonReader.NodeType.Should().Be(JsonNodeType.Property);
     deserializer.JsonReader.Read();
     ODataFeed feed = new ODataFeed();
     deserializer.ReadAndApplyFeedInstanceAnnotationValue("odata.deltaLink", feed, null /*duplicatePropertyNamesChecker*/);
     Assert.AreEqual(new Uri("http://host/relativeUrl", UriKind.Absolute), feed.DeltaLink);
 }
 public void ReadInstanceAnnotationValueShouldReadCollectionOfPrimitiveValues()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.primitiveCollectionAnnotation\":[1,2,3]}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     duplicatePropertyNamesChecker.AddODataPropertyAnnotation("custom.primitiveCollectionAnnotation", "odata.type", "Collection(Edm.Int32)");
     ODataCollectionValue value = (ODataCollectionValue)deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "custom.primitiveCollectionAnnotation");
     TestUtils.AssertODataValueAreEqual(value, new ODataCollectionValue { TypeName = "Collection(Edm.Int32)", Items = new[] { 1, 2, 3 } });
 }
 public void ReadInstanceAnnotationValueShouldReadCollectionOfComplexValues()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.complexCollectionAnnotation\":[{\"StringProperty\":\"StringValue\"}]}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     duplicatePropertyNamesChecker.AddODataPropertyAnnotation("custom.complexCollectionAnnotation", "odata.type", "Collection(TestNamespace.TestComplexType)");
     ODataCollectionValue value = (ODataCollectionValue)deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "custom.complexCollectionAnnotation");
     var odataComplexValue = new ODataComplexValue { TypeName = "TestNamespace.TestComplexType", Properties = new[] { new ODataProperty { Name = "StringProperty", Value = "StringValue" } } };
     var odataCollectionValue = new ODataCollectionValue { TypeName = "Collection(TestNamespace.TestComplexType)", Items = new[] { odataComplexValue } };
     TestUtils.AssertODataValueAreEqual(value, odataCollectionValue);
 }
 public void ReadInstanceAnnotationValueShouldReadComplexValueWithODataTypeInstanceAnnotation()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.ComplexAnnotation\":{\"@odata.type\":\"#TestNamespace.TestComplexType\",\"StringProperty\":\"StringValue\"}}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     ODataComplexValue value = (ODataComplexValue)deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.ComplexAnnotation");
     var odataComplexValue = new ODataComplexValue { TypeName = "TestNamespace.TestComplexType", Properties = new[] { new ODataProperty { Name = "StringProperty", Value = "StringValue" } } };
     TestUtils.AssertODataValueAreEqual(value, odataComplexValue);
 }
 public void ReadInstanceAnnotationValueWithODataTypePropertyAnnotationShouldThrow()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.ComplexAnnotation\":{\"StringProperty\":\"StringValue\"}}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     duplicatePropertyNamesChecker.AddODataPropertyAnnotation("odata.ComplexAnnotation", "odata.type", "TestNamespace.TestComplexType");
     Action action = () => deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.ComplexAnnotation");
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexValueWithPropertyTypeAnnotation("odata.type"));
 }
        /// <summary>
        /// Reads the odata.context annotation.
        /// </summary>
        /// <param name="payloadKind">The payload kind for which to read the context URI.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param>
        /// <param name="failOnMissingContextUriAnnotation">true if the method should fail if the context URI annotation is missing, false if that can be ignored.</param>
        /// <returns>The value of the context URI annotation.</returns>
        internal string ReadContextUriAnnotation(
            ODataPayloadKind payloadKind,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            bool failOnMissingContextUriAnnotation)
        {
            if (this.JsonReader.NodeType != JsonNodeType.Property)
            {
                if (!failOnMissingContextUriAnnotation || payloadKind == ODataPayloadKind.Unsupported)
                {
                    // Do not fail during payload kind detection
                    return null;
                }

                throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_ContextLinkNotFoundAsFirstProperty);
            }

            // Must make sure the input odata.context has a '@' prefix
            string propertyName = this.JsonReader.GetPropertyName();
            if (string.CompareOrdinal(JsonLightConstants.ODataPropertyAnnotationSeparatorChar + ODataAnnotationNames.ODataContext, propertyName) != 0)
            {
                if (!failOnMissingContextUriAnnotation || payloadKind == ODataPayloadKind.Unsupported)
                {
                    // Do not fail during payload kind detection
                    return null;
                }

                throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_ContextLinkNotFoundAsFirstProperty);
            }

            if (duplicatePropertyNamesChecker != null)
            {
                duplicatePropertyNamesChecker.MarkPropertyAsProcessed(propertyName);
            }

            // Read over the property name
            this.JsonReader.ReadNext();
            return this.JsonReader.ReadStringValue();
        }
        /// <summary>
        /// Parses JSON object property starting with the current position of the JSON reader.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use, it will also store the property annotations found.</param>
        /// <param name="readPropertyAnnotationValue">Function called to read property annotation value.</param>
        /// <param name="parsedPropertyName">The name of the property or instance annotation found.</param>
        /// <returns>
        /// PropertyWithValue - a property with value was found. The <paramref name="parsedPropertyName"/> contains the name of the property.
        ///                     The reader is positioned on the property value.
        /// PropertyWithoutValue - a property without a value was found. The <paramref name="parsedPropertyName"/> contains the name of the property.
        ///                        The reader is positioned on the node after property annotations (so either a property or end of object).
        /// ODataInstanceAnnotation - an odata instance annotation was found. The <paramref name="parsedPropertyName"/> contains the name of the annotation.
        ///                      The reader is positioned on the value of the annotation.
        /// CustomInstanceAnnotation - a custom instance annotation was found. The <paramref name="parsedPropertyName"/> contains the name of the annotation.
        ///                      The reader is positioned on the value of the annotation.
        /// MetadataReferenceProperty - a property which is a reference into the metadata was found.
        ///                             The reader is positioned on the value of the property.
        /// EndOfObject - end of the object scope was reached and no properties are to be reported. The <paramref name="parsedPropertyName"/> is null.
        ///               This can only happen if there's a property annotation which is ignored (for example custom one) at the end of the object.
        /// </returns>
        private PropertyParsingResult ParseProperty(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            Func<string, object> readPropertyAnnotationValue,
            out string parsedPropertyName)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(readPropertyAnnotationValue != null, "readPropertyAnnotationValue != null");
            string lastPropertyAnnotationNameFound = null;
            parsedPropertyName = null;

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string nameFromReader = this.JsonReader.GetPropertyName();

                string propertyNameFromReader, annotationNameFromReader;
                bool isPropertyAnnotation = TryParsePropertyAnnotation(nameFromReader, out propertyNameFromReader, out annotationNameFromReader);

                bool isInstanceAnnotation = false;
                if (!isPropertyAnnotation)
                {
                    isInstanceAnnotation = IsInstanceAnnotation(nameFromReader);
                    propertyNameFromReader = isInstanceAnnotation ? nameFromReader.Substring(1) : nameFromReader;
                }

                // If parsedPropertyName is set and is different from the property name the reader is currently on,
                // we have parsed a property annotation for a different property than the one at the current position.
                if (parsedPropertyName != null && string.CompareOrdinal(parsedPropertyName, propertyNameFromReader) != 0)
                {
                    if (ODataJsonLightReaderUtils.IsAnnotationProperty(parsedPropertyName))
                    {
                        throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName));
                    }

                    return PropertyParsingResult.PropertyWithoutValue;
                }

                if (isPropertyAnnotation)
                {
                    // If this is a unknown odata annotation targeting a property, we skip over it. See remark on the method SkippedOverUnknownODataAnnotation() for detailed explaination.
                    // Note that we don't skip over unknown odata annotations targeting another annotation. We don't allow annotations (except odata.type) targeting other annotations,
                    // so this.ProcessPropertyAnnotation() will test and fail for that case.
                    if (!ODataJsonLightReaderUtils.IsAnnotationProperty(propertyNameFromReader) && this.SkippedOverUnknownODataAnnotation(annotationNameFromReader))
                    {
                        continue;
                    }

                    // We have another property annotation for the same property we parsed.
                    parsedPropertyName = propertyNameFromReader;
                    lastPropertyAnnotationNameFound = annotationNameFromReader;

                    this.ProcessPropertyAnnotation(propertyNameFromReader, annotationNameFromReader, duplicatePropertyNamesChecker, readPropertyAnnotationValue);
                    continue;
                }

                // If this is a unknown odata annotation, skip over it. See remark on the method SkippedOverUnknownODataAnnotation() for detailed explaination.
                if (this.SkippedOverUnknownODataAnnotation(propertyNameFromReader))
                {
                    continue;
                }

                // We are encountering the property name for the first time.
                // Read over the property name.
                this.JsonReader.Read();
                parsedPropertyName = propertyNameFromReader;

                if (!isInstanceAnnotation && ODataJsonLightUtils.IsMetadataReferenceProperty(propertyNameFromReader))
                {
                    return PropertyParsingResult.MetadataReferenceProperty;
                }

                if (!isInstanceAnnotation && !ODataJsonLightReaderUtils.IsAnnotationProperty(propertyNameFromReader))
                {
                    // Normal property
                    return PropertyParsingResult.PropertyWithValue;
                }

                // Handle 'odata.XXXXX' annotations
                if (isInstanceAnnotation && ODataJsonLightReaderUtils.IsODataAnnotationName(propertyNameFromReader))
                {
                    return PropertyParsingResult.ODataInstanceAnnotation;
                }

                // Handle custom annotations
                return PropertyParsingResult.CustomInstanceAnnotation;
            }

            this.AssertJsonCondition(JsonNodeType.EndObject);
            if (parsedPropertyName != null)
            {
                if (ODataJsonLightReaderUtils.IsAnnotationProperty(parsedPropertyName))
                {
                    throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName));
                }

                return PropertyParsingResult.PropertyWithoutValue;
            }

            return PropertyParsingResult.EndOfObject;
        }
 public void ReadEntryInstanceAnnotationShouldReadCustomInstanceAnnotationValue()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.Int32Annotation\":123}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     object value = deserializer.ReadEntryInstanceAnnotation("custom.Int32Annotation", false /*anyPropertyFound*/, true /*typeAnnotationFound*/, duplicatePropertyNamesChecker);
     Assert.AreEqual(123, value);
 }
        /// <summary>
        /// Read the start of the top-level data wrapper in JSON responses.
        /// </summary>
        /// <param name="payloadKind">The kind of payload we are reading; this guides the parsing of the context URI.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param>
        /// <param name="isReadingNestedPayload">true if we are deserializing a nested payload, e.g. an entry, a feed or a collection within a parameters payload.</param>
        /// <param name="allowEmptyPayload">true if we allow a comletely empty payload; otherwise false.</param>
        /// <returns>The value of the context URI annotation (or null if it was not found).</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet when not reading a nested payload.
        /// Post-Condition: The reader is positioned on the first property of the payload after having read (or skipped) the context URI property.
        ///                 Or the reader is positioned on an end-object node if there are no properties (other than the context URI which is required in responses and optional in requests).
        /// </remarks>
        private string ReadPayloadStartImplementation(
            ODataPayloadKind payloadKind,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            bool isReadingNestedPayload,
            bool allowEmptyPayload)
        {
            this.JsonReader.AssertNotBuffering();
            Debug.Assert(isReadingNestedPayload || this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: JSON reader must not have been used yet when not reading a nested payload.");

            if (!isReadingNestedPayload)
            {
                // Position the reader on the first node inside the outermost object.
                this.JsonReader.Read();

                if (allowEmptyPayload && this.JsonReader.NodeType == JsonNodeType.EndOfInput)
                {
                    return null;
                }

                // Read the start object node and position the reader on the first property
                // (or the end object node).
                this.JsonReader.ReadStartObject();

                if (payloadKind != ODataPayloadKind.Error)
                {
                    // Skip over the context URI annotation in request payloads or when we've already read it
                    // during payload kind detection.
                    bool failOnMissingContextUriAnnotation = this.jsonLightInputContext.ReadingResponse;

                    // In responses we expect the context URI to be the first thing in the payload
                    // (except for error payloads). In requests we ignore the context URI.
                    return this.ReadContextUriAnnotation(payloadKind, duplicatePropertyNamesChecker, failOnMissingContextUriAnnotation);
                }

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

            return null;
        }
        public void ReadInstanceAnnotationValueShouldThrowIfWireTypeAndModelTypeConflict()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.DateTimeOffsetAnnotation\":\"2013-01-25T09:50Z\"}");
            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);

            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
            duplicatePropertyNamesChecker.AddODataPropertyAnnotation("custom.DateTimeOffsetAnnotation", "odata.type", "Edm.String");

            Action testSubject = () => deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "custom.DateTimeOffsetAnnotation");
            testSubject.ShouldThrow<ODataException>().WithMessage(ErrorStrings.ValidationUtils_IncompatibleType("Edm.String", "Edm.DateTimeOffset"));
        }
 public void ReadTopLevelFeedAnnotationsForFeedEndAndNonBufferingShouldReadRemainingInstanceAnnotationsAfterValue()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.after\":456}");
     AdvanceReaderToFirstProperty(deserializer.JsonReader);
     var feed = new ODataFeed();
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, false /*forFeedStart*/, false /*readAllFeedProperties*/);
     Assert.AreEqual(1, feed.InstanceAnnotations.Count);
     TestUtils.AssertODataValueAreEqual(new ODataPrimitiveValue(456), feed.InstanceAnnotations.Single(ia => ia.Name == "custom.after").Value);
 }
 public void ReadTopLevelFeedAnnotationsForFeedEndAndNonBufferingShouldSkipInstanceAnnotationsBasedOnReaderSettings()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.after\":456}", shouldReadAndValidateCustomInstanceAnnotations: false);
     AdvanceReaderToFirstProperty(deserializer.JsonReader);
     var feed = new ODataFeed();
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, false /*forFeedStart*/, false /*readAllFeedProperties*/);
     Assert.AreEqual(0, feed.InstanceAnnotations.Count);
 }
示例#29
0
            /// <summary>
            /// Constructor to create a new entry scope.
            /// </summary>
            /// <param name="entry">The entry for the new scope.</param>
            /// <param name="serializationInfo">The serialization info for the current entry.</param>
            /// <param name="navigationSource">The navigation source we are going to write entities for.</param>
            /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param>
            /// <param name="skipWriting">true if the content of the scope to create should not be written.</param>
            /// <param name="writingResponse">true if we are writing a response, false if it's a request.</param>
            /// <param name="writerBehavior">The <see cref="ODataWriterBehavior"/> instance controlling the behavior of the writer.</param>
            /// <param name="selectedProperties">The selected properties of this scope.</param>
            /// <param name="odataUri">The ODataUri info of this scope.</param>
            /// <param name="enableValidation">Enable validation or not.</param>
            internal EntryScope(ODataEntry entry, ODataFeedAndEntrySerializationInfo serializationInfo, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, bool writingResponse, ODataWriterBehavior writerBehavior, SelectedPropertiesNode selectedProperties, ODataUri odataUri, bool enableValidation = true)
                : base(WriterState.Entry, entry, navigationSource, entityType, skipWriting, selectedProperties, odataUri)
            {
                Debug.Assert(writerBehavior != null, "writerBehavior != null");

                if (entry != null)
                {
                    this.duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(writerBehavior.AllowDuplicatePropertyNames, writingResponse, !enableValidation);
                }

                this.serializationInfo = serializationInfo;
            }
        public void ReadTimeOfDayTypeInstanceAnnotationValueWillReadAsCorrectTypeFromModel()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.TimeOfDayAnnotation\":\"12:30:40.900\"}");
            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            object value = deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "custom.TimeOfDayAnnotation");
            value.Should().BeOfType<TimeOfDay>();
            value.Should().Be(TimeOfDay.Parse("12:30:40.900"));
        }
 public void ReadTopLevelFeedAnnotationsForFeedEndAndBufferingShouldSkipAllValues()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.before\":123,\"value\":[],\"@custom.after\":456}");
     AdvanceReaderToFirstProperty(deserializer.JsonReader);
     var feed = new ODataFeed();
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, false /*forFeedStart*/, true /*readAllFeedProperties*/);
     feed.InstanceAnnotations.Should().BeEmpty();
 }
 public void ReadInstanceAnnotationValueWhenODataTypeAnnotationIsMissingForComplexValue()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.ComplexAnnotation\":{}}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     object resultTmp = deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.ComplexAnnotation");
     resultTmp.As<ODataComplexValue>().Properties.Count().Should().Be(0);
     resultTmp.As<ODataComplexValue>().TypeName.Should().BeNull();
 }