Пример #1
0
        /// <summary>
        /// Reads an inner error payload.
        /// </summary>
        /// <param name="recursionDepth">The number of times this method has been called recursively.</param>
        /// <returns>An <see cref="ODataInnerError"/> representing the read inner error.</returns>
        /// <remarks>
        /// Pre-Condition:  any                         - will throw if not StartObject
        /// Post-Condition: JsonNodeType.Property       - The next property in the error value
        ///                 JsonNodeType.EndObject      - The end of the error value
        /// </remarks>
        private ODataInnerError ReadInnerError(int recursionDepth)
        {
            Debug.Assert(this.JsonReader.DisableInStreamErrorDetection, "JsonReader.DisableInStreamErrorDetection");
            this.JsonReader.AssertNotBuffering();

            ValidationUtils.IncreaseAndValidateRecursionDepth(ref recursionDepth, this.MessageReaderSettings.MessageQuotas.MaxNestingDepth);

            this.JsonReader.ReadStartObject();

            ODataInnerError innerError = new ODataInnerError();

            ODataVerboseJsonReaderUtils.ErrorPropertyBitMask propertiesFoundBitField = ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.None;
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                switch (propertyName)
                {
                case JsonConstants.ODataErrorInnerErrorMessageName:
                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.MessageValue,
                        JsonConstants.ODataErrorInnerErrorMessageName);
                    innerError.Message = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorInnerErrorMessageName);
                    break;

                case JsonConstants.ODataErrorInnerErrorTypeNameName:
                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.TypeName,
                        JsonConstants.ODataErrorInnerErrorTypeNameName);
                    innerError.TypeName = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorInnerErrorTypeNameName);
                    break;

                case JsonConstants.ODataErrorInnerErrorStackTraceName:
                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.StackTrace,
                        JsonConstants.ODataErrorInnerErrorStackTraceName);
                    innerError.StackTrace = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorInnerErrorStackTraceName);
                    break;

                case JsonConstants.ODataErrorInnerErrorInnerErrorName:
                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.InnerError,
                        JsonConstants.ODataErrorInnerErrorInnerErrorName);
                    innerError.InnerError = this.ReadInnerError(recursionDepth);
                    break;

                default:
                    // skip any unsupported properties in the inner error
                    this.JsonReader.SkipValue();
                    break;
                }
            }

            this.JsonReader.ReadEndObject();
            this.JsonReader.AssertNotBuffering();
            return(innerError);
        }
Пример #2
0
        /// <summary>
        /// Reads the properties of an entity reference link.
        /// </summary>
        /// <param name="entityReferenceLinks">The <see cref="ODataEntityReferenceLinks"/> instance to set the read property values on.</param>
        /// <param name="propertiesFoundBitField">The bit field with all the properties already read.</param>
        /// <returns>true if the method found the 'results' property; otherwise false.</returns>
        private bool ReadEntityReferenceLinkProperties(
            ODataEntityReferenceLinks entityReferenceLinks,
            ref ODataVerboseJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask propertiesFoundBitField)
        {
            Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null");
            this.JsonReader.AssertNotBuffering();

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                switch (propertyName)
                {
                case JsonConstants.ODataResultsName:
                    ODataVerboseJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.Results,
                        JsonConstants.ODataResultsName);
                    this.JsonReader.AssertNotBuffering();
                    return(true);

                case JsonConstants.ODataCountName:
                    ODataVerboseJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.Count,
                        JsonConstants.ODataCountName);
                    object countValue = this.JsonReader.ReadPrimitiveValue();
                    long?  count      = (long?)ODataVerboseJsonReaderUtils.ConvertValue(
                        countValue,
                        EdmCoreModel.Instance.GetInt64(true),
                        this.MessageReaderSettings,
                        this.Version,
                        /*validateNullValue*/ true,
                        propertyName);
                    ODataVerboseJsonReaderUtils.ValidateCountPropertyInEntityReferenceLinks(count);
                    entityReferenceLinks.Count = count;
                    break;

                case JsonConstants.ODataNextLinkName:
                    ODataVerboseJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.NextPageLink,
                        JsonConstants.ODataNextLinkName);
                    string nextLinkString = this.JsonReader.ReadStringValue(JsonConstants.ODataNextLinkName);
                    ODataVerboseJsonReaderUtils.ValidateEntityReferenceLinksStringProperty(nextLinkString, JsonConstants.ODataNextLinkName);
                    entityReferenceLinks.NextPageLink = this.ProcessUriFromPayload(nextLinkString);
                    break;

                default:
                    // Skip all unrecognized properties
                    this.JsonReader.SkipValue();
                    break;
                }
            }

            this.JsonReader.AssertNotBuffering();
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Reads the type name from the value of a __metadata property. All other properties in the __metadata property value are ignored.
        /// </summary>
        /// <returns>The type name found, or null if none was found.</returns>
        /// <remarks>
        /// This method can be used in buffering and non-buffering mode.
        ///
        /// Pre-Condition:  Fails if the current node is not a JsonNodeType.StartObject
        /// Post-Condition: JsonNodeType.Property - the next property after the __metadata property value.
        ///                 JsonNodeType.EndObject - if the __metadata property was the last property in the object.
        /// </remarks>
        internal string ReadTypeNameFromMetadataPropertyValue()
        {
            DebugUtils.CheckNoExternalCallers();

            string typeName = null;

            // The value of the __metadata property must be an object
            if (this.JsonReader.NodeType != JsonNodeType.StartObject)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MetadataPropertyMustHaveObjectValue(this.JsonReader.NodeType));
            }

            this.JsonReader.ReadStartObject();

            // Go over the properties and look for the type property.
            ODataVerboseJsonReaderUtils.MetadataPropertyBitMask propertiesFoundBitField = 0;
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal(JsonConstants.ODataMetadataTypeName, propertyName) == 0)
                {
                    ODataVerboseJsonReaderUtils.VerifyMetadataPropertyNotFound(
                        ref propertiesFoundBitField,
                        ODataVerboseJsonReaderUtils.MetadataPropertyBitMask.Type,
                        JsonConstants.ODataMetadataTypeName);
                    object typeNameValue = this.JsonReader.ReadPrimitiveValue();
                    typeName = typeNameValue as string;
                    if (typeName == null)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidTypeName(typeNameValue));
                    }
                }
                else
                {
                    // Skip over the property value.
                    this.JsonReader.SkipValue();
                }
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "Only Property or EndObject can occur in Object scope.");
            this.JsonReader.ReadEndObject();

            Debug.Assert(
                this.JsonReader.NodeType == JsonNodeType.Property || this.JsonReader.NodeType == JsonNodeType.EndObject,
                "Post-Condition: expected JsonNodeType.Property or JsonNodeType.EndObject");

            return(typeName);
        }
Пример #4
0
        /// <summary>
        /// Reads a primitive value.
        /// </summary>
        /// <param name="expectedValueTypeReference">The expected type reference of the value.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>The value of the primitive value.</returns>
        /// <remarks>
        /// Pre-Condition:  none - Fails if the current node is not a JsonNodeType.PrimitiveValue
        /// Post-Condition: almost anything - the node after the primitive value.
        ///
        /// Made internal only for testability.
        /// </remarks>
        internal object ReadPrimitiveValue(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            this.JsonReader.AssertNotBuffering();
            object result;

            if (expectedValueTypeReference != null && expectedValueTypeReference.IsSpatial())
            {
                result = ODataJsonReaderCoreUtils.ReadSpatialValue(
                    this.JsonReader,
                    /*insideJsonObjectValue*/ false,
                    this.VerboseJsonInputContext,
                    expectedValueTypeReference,
                    validateNullValue,
                    this.recursionDepth,
                    propertyName);
            }
            else
            {
                result = this.JsonReader.ReadPrimitiveValue();

                if (expectedValueTypeReference != null && !this.MessageReaderSettings.DisablePrimitiveTypeConversion)
                {
                    result = ODataVerboseJsonReaderUtils.ConvertValue(
                        result,
                        expectedValueTypeReference,
                        this.MessageReaderSettings,
                        this.Version,
                        validateNullValue,
                        propertyName);
                }
            }

            this.JsonReader.AssertNotBuffering();

            return(result);
        }
Пример #5
0
        /// <summary>
        /// Reads a primitive, complex or collection value.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the property value.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable.</param>
        /// <returns>The value of the property read.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue   - the value of the property is a primitive value
        ///                 JsonNodeType.StartObject      - the value of the property is an object
        ///                 JsonNodeType.StartArray       - the value of the property is an array - method will fail in this case.
        /// Post-Condition: almost anything - the node after the property value.
        ///
        /// Returns the value of the property read, which can be one of:
        /// - null
        /// - primitive value
        /// - <see cref="ODataComplexValue"/>
        /// - <see cref="ODataCollectionValue"/>
        /// </remarks>
        private object ReadNonEntityValueImplementation(
            IEdmTypeReference expectedTypeReference,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            bool validateNullValue,
            string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                this.JsonReader.NodeType == JsonNodeType.PrimitiveValue || this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray,
                "Pre-Condition: expected JsonNodeType.PrimitiveValue or JsonNodeType.StartObject or JsonNodeType.StartArray");
            Debug.Assert(
                expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(),
                "Only primitive, complex or collection types can be read by this method.");
            Debug.Assert(
                expectedTypeReference == null || collectionValidator == null,
                "If an expected value type reference is specified, no collection validator must be provided.");
            this.JsonReader.AssertNotBuffering();

            // Property values can be only primitives or objects. No property can have a JSON array value.
            JsonNodeType nodeType = this.JsonReader.NodeType;

            if (nodeType == JsonNodeType.StartArray)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType));
            }

            // Try to read a null value
            object result;

            if (ODataJsonReaderCoreUtils.TryReadNullValue(
                    this.JsonReader,
                    this.VerboseJsonInputContext,
                    expectedTypeReference,
                    validateNullValue,
                    propertyName))
            {
                result = null;
            }
            else
            {
                // Read the payload type name
                string payloadTypeName = this.FindTypeNameInPayload();

                SerializationTypeNameAnnotation serializationTypeNameAnnotation;
                EdmTypeKind       targetTypeKind;
                IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(
                    EdmTypeKind.None,
                    /*defaultPrimitivePayloadType*/ null,
                    expectedTypeReference,
                    payloadTypeName,
                    this.Model,
                    this.MessageReaderSettings,
                    this.Version,
                    this.GetNonEntityValueKind,
                    out targetTypeKind,
                    out serializationTypeNameAnnotation);

                switch (targetTypeKind)
                {
                case EdmTypeKind.Primitive:
                    Debug.Assert(targetTypeReference == null || targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type.");
                    IEdmPrimitiveTypeReference primitiveTargetTypeReference = targetTypeReference == null ? null : targetTypeReference.AsPrimitive();
                    if (payloadTypeName != null && !primitiveTargetTypeReference.IsSpatial())
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName));
                    }

                    result = this.ReadPrimitiveValue(
                        primitiveTargetTypeReference,
                        validateNullValue,
                        propertyName);
                    break;

                case EdmTypeKind.Complex:
                    Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type.");
                    result = this.ReadComplexValueImplementation(
                        targetTypeReference == null ? null : targetTypeReference.AsComplex(),
                        payloadTypeName,
                        serializationTypeNameAnnotation,
                        duplicatePropertyNamesChecker);
                    break;

                case EdmTypeKind.Collection:
                    Debug.Assert(this.Version >= ODataVersion.V3, "Type resolution should already fail if we would decide to read a collection value in V1/V2 payload.");
                    IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference);
                    result = this.ReadCollectionValueImplementation(
                        collectionTypeReference,
                        payloadTypeName,
                        serializationTypeNameAnnotation);
                    break;

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

                // If we have no expected type make sure the collection items are of the same kind and specify the same name.
                if (collectionValidator != null)
                {
                    string payloadTypeNameFromResult = ODataVerboseJsonReaderUtils.GetPayloadTypeName(result);
                    Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference.");
                    collectionValidator.ValidateCollectionItem(payloadTypeNameFromResult, targetTypeKind);
                }
            }

            this.JsonReader.AssertNotBuffering();
            return(result);
        }
Пример #6
0
        /// <summary>
        /// Read a top-level error.
        /// </summary>
        /// <returns>An <see cref="ODataError"/> representing the read error.</returns>
        internal ODataError ReadTopLevelError()
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            Debug.Assert(!this.JsonReader.DisableInStreamErrorDetection, "!JsonReader.DisableInStreamErrorDetection");
            this.JsonReader.AssertNotBuffering();

            // prevent the buffering JSON reader from detecting in-stream errors - we read the error ourselves
            // to throw proper exceptions
            this.JsonReader.DisableInStreamErrorDetection = true;

            ODataError error = new ODataError();

            try
            {
                // Read the start of the payload (no "d" wrapper for top-level errors)
                this.ReadPayloadStart(/*isReadingNestedPayload*/ false, /*expectResponseWrapper*/ false);

                // Read the start of the error object
                this.JsonReader.ReadStartObject();

                ODataVerboseJsonReaderUtils.ErrorPropertyBitMask propertiesFoundBitField = ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.None;
                while (this.JsonReader.NodeType == JsonNodeType.Property)
                {
                    string propertyName = this.JsonReader.ReadPropertyName();
                    if (string.CompareOrdinal(JsonConstants.ODataErrorName, propertyName) != 0)
                    {
                        // we only allow a single 'error' property for a top-level error object
                        throw new ODataException(Strings.ODataJsonErrorDeserializer_TopLevelErrorWithInvalidProperty(propertyName));
                    }

                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.Error, JsonConstants.ODataErrorName);

                    this.JsonReader.ReadStartObject();

                    while (this.JsonReader.NodeType == JsonNodeType.Property)
                    {
                        propertyName = this.JsonReader.ReadPropertyName();
                        switch (propertyName)
                        {
                        case JsonConstants.ODataErrorCodeName:
                            ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.Code, JsonConstants.ODataErrorCodeName);
                            error.ErrorCode = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorCodeName);
                            break;

                        case JsonConstants.ODataErrorMessageName:
                            ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.Message, JsonConstants.ODataErrorMessageName);
                            this.JsonReader.ReadStartObject();

                            while (this.JsonReader.NodeType == JsonNodeType.Property)
                            {
                                propertyName = this.JsonReader.ReadPropertyName();
                                switch (propertyName)
                                {
                                case JsonConstants.ODataErrorMessageLanguageName:
                                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.MessageLanguage, JsonConstants.ODataErrorMessageLanguageName);
                                    error.MessageLanguage = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorMessageLanguageName);
                                    break;

                                case JsonConstants.ODataErrorMessageValueName:
                                    ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.MessageValue, JsonConstants.ODataErrorMessageValueName);
                                    error.Message = this.JsonReader.ReadStringValue(JsonConstants.ODataErrorMessageValueName);
                                    break;

                                default:
                                    // we only allow a 'lang' and 'value' properties in the value of the 'message' property
                                    throw new ODataException(Strings.ODataJsonErrorDeserializer_TopLevelErrorMessageValueWithInvalidProperty(propertyName));
                                }
                            }

                            this.JsonReader.ReadEndObject();
                            break;

                        case JsonConstants.ODataErrorInnerErrorName:
                            ODataVerboseJsonReaderUtils.VerifyErrorPropertyNotFound(ref propertiesFoundBitField, ODataVerboseJsonReaderUtils.ErrorPropertyBitMask.InnerError, JsonConstants.ODataErrorInnerErrorName);
                            error.InnerError = this.ReadInnerError(0 /* recursionDepth */);
                            break;

                        default:
                            // we only allow a 'code', 'message' and 'innererror' properties in the value of the 'error' property
                            throw new ODataException(Strings.ODataVerboseJsonErrorDeserializer_TopLevelErrorValueWithInvalidProperty(propertyName));
                        }
                    }

                    this.JsonReader.ReadEndObject();
                }

                // Read the end of the error object
                this.JsonReader.ReadEndObject();

                // Read the end of the response (no "d" wrapper for top-level errors)
                this.ReadPayloadEnd(/*isReadingNestedPayload*/ false, /*expectResponseWrapper*/ false);
            }
            finally
            {
                this.JsonReader.DisableInStreamErrorDetection = false;
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: JsonNodeType.EndOfInput");
            this.JsonReader.AssertNotBuffering();

            return(error);
        }