/// <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
            }));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataJsonLightContextUriParseResult"/> class.
        /// </summary>
        /// <param name="model">The model to use when resolving the target of the URI.</param>
        /// <param name="contextUriFromPayload">The context URI read from the payload.</param>
        private ODataJsonLightContextUriParser(IEdmModel model, Uri contextUriFromPayload)
        {
            Debug.Assert(model != null, "model != null");

            if (!model.IsUserModel())
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_NoModel);
            }

            this.model       = model;
            this.parseResult = new ODataJsonLightContextUriParseResult(contextUriFromPayload);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataJsonLightContextUriParseResult"/> class.
        /// </summary>
        /// <param name="model">The model to use when resolving the target of the URI.</param>
        /// <param name="contextUriFromPayload">The context URI read from the payload.</param>
        private ODataJsonLightContextUriParser(IEdmModel model, Uri contextUriFromPayload)
        {
            Debug.Assert(model != null, "model != null");

            if (!model.IsUserModel())
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_NoModel);
            }

            this.model = model;
            this.parseResult = new ODataJsonLightContextUriParseResult(contextUriFromPayload);
        }
        /// <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>
        /// <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 void ReadPayloadStart(
            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.");

            string contextUriAnnotationValue = this.ReadPayloadStartImplementation(
                payloadKind,
                duplicatePropertyNamesChecker,
                isReadingNestedPayload,
                allowEmptyPayload);

            ODataJsonLightContextUriParseResult parseResult = null;

            // 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)
            {
                parseResult = this.jsonLightInputContext.PayloadKindDetectionState == null
                    ? null
                    : this.jsonLightInputContext.PayloadKindDetectionState.ContextUriParseResult;
                if (parseResult == null && contextUriAnnotationValue != null)
                {
                    parseResult = ODataJsonLightContextUriParser.Parse(
                        this.Model,
                        contextUriAnnotationValue,
                        payloadKind,
                        this.Version,
                        this.MessageReaderSettings.ReaderBehavior,
                        this.JsonLightInputContext.ReadingResponse);
                }
            }

            this.contextUriParseResult = parseResult;
#if DEBUG
            this.contextUriParseResultReady = true;
#endif
        }
        /// <summary>
        /// Validates that the parsed context URI from the payload is consistent with the expected
        /// collection item type when reading collection payloads.
        /// </summary>
        /// <param name="contextUriParseResult">The parse result of the context URI from the payload.</param>
        /// <param name="expectedItemTypeReference">The expected item type of the collection items.</param>
        /// <returns>The actual item type of the collection items.</returns>
        internal static IEdmTypeReference ValidateCollectionContextUriAndGetPayloadItemTypeReference(
            ODataJsonLightContextUriParseResult contextUriParseResult,
            IEdmTypeReference expectedItemTypeReference)
        {
            if (contextUriParseResult == null || contextUriParseResult.EdmType == null)
            {
                return expectedItemTypeReference;
            }

            Debug.Assert(contextUriParseResult.EdmType is IEdmCollectionType, "contextUriParseResult.EdmType is IEdmCollectionType");
            IEdmCollectionType actualCollectionType = (IEdmCollectionType)contextUriParseResult.EdmType;
            if (expectedItemTypeReference != null)
            {
                // We allow co-variance in collection types (e.g., expecting the item type of Geography from a payload of Collection(GeographyPoint).
                if (!expectedItemTypeReference.IsAssignableFrom(actualCollectionType.ElementType))
                {
                    throw new ODataException(OData.Core.Strings.ReaderValidationUtils_ContextUriDoesNotReferTypeAssignableToExpectedType(
                        UriUtils.UriToString(contextUriParseResult.ContextUri),
                        actualCollectionType.ElementType.ODataFullName(),
                        expectedItemTypeReference.ODataFullName()));
                }
            }

            return actualCollectionType.ElementType;
        }
        /// <summary>
        /// Validates that the parsed context URI from the payload is consistent with the expected
        /// entity set and entity type when reading a feed or entry payload.
        /// </summary>
        /// <param name="contextUriParseResult">The parse result of the context URI from the payload.</param>
        /// <param name="scope">The top-level scope representing the reader state.</param>
        /// <param name="updateScope">Whether to update scope when validating.</param>
        internal static void ValidateFeedOrEntryContextUri(ODataJsonLightContextUriParseResult contextUriParseResult, ODataReaderCore.Scope scope, bool updateScope)
        {
            if (contextUriParseResult.EdmType is IEdmCollectionType)
            {
                ValidateFeedContextUri(contextUriParseResult, scope, updateScope);
                return;
            }

            Debug.Assert(contextUriParseResult != null, "contextUriParseResult != null");
            Debug.Assert(
                contextUriParseResult.NavigationSource != null || contextUriParseResult.EdmType != null,
                "contextUriParseResult.EntitySet != null || contextUriParseResult.EdmType != null");
            Debug.Assert(contextUriParseResult.EdmType is IEdmEntityType, "contextUriParseResult.StructuredType is IEdmEntityType");

            // Set the navigation source name or make sure the navigation source names match.
            if (scope.NavigationSource == null)
            {
                if (updateScope)
                {
                    scope.NavigationSource = contextUriParseResult.NavigationSource;
                }
            }
            else if (contextUriParseResult.NavigationSource != null && string.CompareOrdinal(scope.NavigationSource.FullNavigationSourceName(), contextUriParseResult.NavigationSource.FullNavigationSourceName()) != 0)
            {
                throw new ODataException(Strings.ReaderValidationUtils_ContextUriValidationInvalidExpectedEntitySet(
                    UriUtils.UriToString(contextUriParseResult.ContextUri),
                    contextUriParseResult.NavigationSource.FullNavigationSourceName(),
                    scope.NavigationSource.FullNavigationSourceName()));
            }

            // Set the entity type or make sure the entity types are assignable.
            IEdmEntityType payloadEntityType = (IEdmEntityType)contextUriParseResult.EdmType;
            if (scope.EntityType == null)
            {
                if (updateScope)
                {
                    scope.EntityType = payloadEntityType;
                }
            }
            else if (scope.EntityType.IsAssignableFrom(payloadEntityType))
            {
                if (updateScope)
                {
                    scope.EntityType = payloadEntityType;
                }
            }
            else if (!payloadEntityType.IsAssignableFrom(scope.EntityType))
            {
                throw new ODataException(Strings.ReaderValidationUtils_ContextUriValidationInvalidExpectedEntityType(
                    UriUtils.UriToString(contextUriParseResult.ContextUri),
                    contextUriParseResult.EdmType.ODataFullName(),
                    scope.EntityType.FullName()));
            }
        }
 /// <summary>
 /// The validate feed context uri.
 /// </summary>
 /// <param name="contextUriParseResult">
 /// The context uri parse result.
 /// </param>
 /// <param name="scope">
 /// The scope.
 /// </param>
 /// <param name="updateScope">
 /// The update scope.
 /// </param>
 private static void ValidateFeedContextUri(ODataJsonLightContextUriParseResult contextUriParseResult, ODataReaderCore.Scope scope, bool updateScope)
 {
     // TODO: add validation logic for a feed context uri
 }
        /// <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
                });
        }
        private void CompareContextUriParseResults(ODataJsonLightContextUriParseResult expected, ODataJsonLightContextUriParseResult actual, string expectedPathStr)
        {
            this.Assert.AreEqual(expected.MetadataDocumentUri, actual.MetadataDocumentUri, "Metadata document URIs don't match.");
            this.Assert.AreEqual(expected.NavigationSource, actual.NavigationSource, "Entity sets don't match.");
            if (expected.EdmType is IEdmCollectionType)
            {
                this.Assert.AreEqual(((IEdmCollectionType)expected.EdmType).ElementType.Definition, ((IEdmCollectionType)actual.EdmType).ElementType.Definition, "Entity types don't match.");
            }
            else
            {
                this.Assert.AreEqual(expected.EdmType, actual.EdmType, "Entity types don't match.");
            }

            this.Assert.AreEqual(expected.SelectQueryOption, actual.SelectQueryOption, "Select query option properties don't match.");
            if (expectedPathStr != null)
            {
                this.Assert.IsNotNull(actual.Path, "Path should not be null");
                this.Assert.AreEqual(expectedPathStr, actual.Path.ToContextUrlPathString(), "Path not equal");
            }

            this.Assert.AreEqual(expected.DeltaKind, actual.DeltaKind, "Delta kind doesn't match.");
        }