Beispiel #1
0
        /// <summary>
        /// Gets the type name from the given <paramref name="value"/>.
        /// </summary>
        /// <param name="value">The value to get the type name from. This can be an ODataPrimitiveValue, an ODataComplexValue, an ODataCollectionValue or a Clr primitive object.</param>
        /// <returns>The type name for the given <paramref name="value"/>.</returns>
        protected static string GetTypeNameFromValue(object value)
        {
            Debug.Assert(value != null, "value != null");

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                return(EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType()).ODataFullName());
            }

            ODataComplexValue complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                return(complexValue.TypeName);
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                return(collectionValue.TypeName);
            }

            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());

            if (primitiveTypeReference == null)
            {
                throw new ODataException(Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
            }

            return(primitiveTypeReference.ODataFullName());
        }
        /// <summary>
        /// Gets the type name from the given <paramref name="value"/>.
        /// </summary>
        /// <param name="value">The value to get the type name from. This can be an ODataPrimitiveValue, an ODataComplexValue, an ODataCollectionValue or a Clr primitive object.</param>
        /// <returns>The type name for the given <paramref name="value"/>.</returns>
        protected static string GetTypeNameFromValue(object value)
        {
            Debug.Assert(value != null, "value != null");

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                // primitiveValueTypeReference == null means: the EDM type of the primitive value cannot be determined.
                // This could possibly be due to value being an unsigned int.
                // In this case, simply return null because:
                //   - If the property is regular property, the type is not needed since service model knows its exact type.
                //   - If the property is dynamic property, ODL does not support dynamic property containing unsigned int value
                //     since we don't know its underlying type as well as how to serialize it.
                IEdmPrimitiveTypeReference primitiveValueTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType());
                return(primitiveValueTypeReference == null ? null : primitiveValueTypeReference.ODataFullName());
            }

            ODataComplexValue complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                return(complexValue.TypeName);
            }

            ODataEnumValue enumValue = value as ODataEnumValue;

            if (enumValue != null)
            {
                return(enumValue.TypeName);
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                return(EdmLibraryExtensions.GetCollectionTypeFullName(collectionValue.TypeName));
            }

            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());

            if (primitiveTypeReference == null)
            {
                throw new ODataException(Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
            }

            return(primitiveTypeReference.ODataFullName());
        }
        /// <summary>
        /// Reads an annotation's value from the annotation value notation specified on the current element.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the vocabulary term from the metadata.</param>
        /// <param name="attributeValueNotationTypeReference">The type reference indicated by the name of the attribute used in attribute value notation.
        ///   For example, if the attribute was called "string", this will be a reference to the string type.</param>
        /// <param name="attributeValueNotationAttributeName">The name of the attribute used by attribute avalue notation.</param>
        /// <param name="attributeValueNotationAttributeValue">The value of the attribute used by attribute value notation.</param>
        /// <param name="typeAttributeValue">The value of the "m:type" attribute on the annotation element.</param>
        /// <param name="positionedOnEmptyElement">true if the annotation element is empty, false otherwise.</param>
        /// <param name="model">The edm model instance.</param>
        /// <param name="messageReaderSettings">The message reader settings instance.</param>
        /// <param name="version">The payload version to read.</param>
        /// <returns>The primitive value represented on this element via attribute value notation.</returns>
        private static ODataPrimitiveValue GetValueFromAttributeValueNotation(
            IEdmTypeReference expectedTypeReference,
            IEdmPrimitiveTypeReference attributeValueNotationTypeReference,
            string attributeValueNotationAttributeName,
            string attributeValueNotationAttributeValue,
            string typeAttributeValue,
            bool positionedOnEmptyElement,
            IEdmModel model,
            ODataMessageReaderSettings messageReaderSettings,
            ODataVersion version)
        {
            Debug.Assert(attributeValueNotationTypeReference != null, "attributeValueNotationTypeReference != null");

            if (!positionedOnEmptyElement)
            {
                // If there is content in the body of the element, throw since it's ambiguous whether we should use the value from the attribute or the element content.
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedOnNonEmptyElement(attributeValueNotationAttributeName));
            }

            // If both m:type is present and attribute value notation is being used, they must match.
            // For example, if m:type is "Edm.Int32", but the "string" attribute is also present, we should throw.
            if (typeAttributeValue != null && !string.Equals(attributeValueNotationTypeReference.Definition.ODataFullName(), typeAttributeValue, StringComparison.Ordinal))
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedWithIncompatibleType(typeAttributeValue, attributeValueNotationAttributeName));
            }

            IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType(
                expectedTypeReference,
                EdmTypeKind.Primitive,
                attributeValueNotationTypeReference.Definition,
                attributeValueNotationTypeReference.ODataFullName(),
                attributeValueNotationTypeReference.Definition,
                model,
                messageReaderSettings,
                version);

            return(new ODataPrimitiveValue(AtomValueUtils.ConvertStringToPrimitive(attributeValueNotationAttributeValue, targetTypeReference.AsPrimitive())));
        }
        /// <summary>
        /// Converts the given JSON int value to the expected type as per OData conversion rules for JSON values.
        /// </summary>
        /// <param name="intValue">Int32 value to the converted.</param>
        /// <param name="targetType">Target type to which the int value needs to be converted.</param>
        /// <param name="primitiveTypeReference">Type reference to which the value needs to be converted.</param>
        /// <returns>Object which is in sync with the property type.</returns>
        private static object ConvertInt32Value(int intValue, Type targetType, IEdmPrimitiveTypeReference primitiveTypeReference)
        {
            if (targetType == typeof(Int16))
            {
                return Convert.ToInt16(intValue);
            }

            if (targetType == typeof(Byte))
            {
                return Convert.ToByte(intValue);
            }

            if (targetType == typeof(SByte))
            {
                return Convert.ToSByte(intValue);
            }

            if (targetType == typeof(Single))
            {
                return Convert.ToSingle(intValue);
            }

            if (targetType == typeof(Double))
            {
                return Convert.ToDouble(intValue);
            }

            if (targetType == typeof(Decimal))
            {
                return Convert.ToDecimal(intValue);
            }

            if (targetType == typeof(Int64))
            {
                return Convert.ToInt64(intValue);
            }

            if (targetType != typeof(Int32))
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertInt32(primitiveTypeReference.ODataFullName()));
            }

            return intValue;
        }
        /// <summary>
        /// Creates an exception used when primitive type conversion fails.
        /// </summary>
        /// <param name="targetTypeReference">The target type reference to which the conversion failed.</param>
        /// <param name="innerException">Possible inner exception with more information about the failure.</param>
        /// <param name="stringValue">The string representation for the value.</param>
        /// <returns>The exception object to throw.</returns>
        internal static ODataException GetPrimitiveTypeConversionException(IEdmPrimitiveTypeReference targetTypeReference, Exception innerException, string stringValue)
        {
            Debug.Assert(targetTypeReference != null, "targetTypeReference != null");

            return new ODataException(Strings.ReaderValidationUtils_CannotConvertPrimitiveValue(stringValue, targetTypeReference.ODataFullName()), innerException);
        }
 internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version)
 {
     ExceptionUtils.CheckArgumentNotNull<object>(primitiveValue, "primitiveValue");
     ExceptionUtils.CheckArgumentNotNull<IEdmModel>(model, "model");
     ExceptionUtils.CheckArgumentNotNull<IEdmTypeReference>(expectedTypeReference, "expectedTypeReference");
     ODataUriNullValue value2 = primitiveValue as ODataUriNullValue;
     if (value2 != null)
     {
         if (!expectedTypeReference.IsNullable)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName()));
         }
         IEdmType type = ValidationUtils.ValidateValueTypeName(model, value2.TypeName, expectedTypeReference.Definition.TypeKind);
         if (type.IsSpatial())
         {
             ODataVersionChecker.CheckSpatialValue(version);
         }
         if (!TypePromotionUtils.CanConvertTo(type.ToTypeReference(), expectedTypeReference))
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), value2.TypeName));
         }
         value2.TypeName = expectedTypeReference.ODataFullName();
         return value2;
     }
     IEdmPrimitiveTypeReference reference = expectedTypeReference.AsPrimitiveOrNull();
     if (reference == null)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue));
     }
     object obj2 = CoerceNumericType(primitiveValue, reference.PrimitiveDefinition());
     if (obj2 != null)
     {
         return obj2;
     }
     Type c = primitiveValue.GetType();
     if (!TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(reference)).IsAssignableFrom(c))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(reference.ODataFullName(), primitiveValue));
     }
     return primitiveValue;
 }
Beispiel #7
0
        /// <summary>
        /// Verifies that the given <paramref name="primitiveValue"/> is or can be coerced to <paramref name="expectedTypeReference"/>, and coerces it if necessary.
        /// </summary>
        /// <param name="primitiveValue">An EDM primitive value to verify.</param>
        /// <param name="model">Model to verify against.</param>
        /// <param name="expectedTypeReference">Expected type reference.</param>
        /// <param name="version">The version to use for reading.</param>
        /// <returns>Coerced version of the <paramref name="primitiveValue"/>.</returns>
        internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            ExceptionUtils.CheckArgumentNotNull(primitiveValue, "primitiveValue");
            ExceptionUtils.CheckArgumentNotNull(model, "model");
            ExceptionUtils.CheckArgumentNotNull(expectedTypeReference, "expectedTypeReference");

            // First deal with null literal
            ODataUriNullValue nullValue = primitiveValue as ODataUriNullValue;

            if (nullValue != null)
            {
                if (!expectedTypeReference.IsNullable)
                {
                    throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName()));
                }

                IEdmType actualResolvedType = ValidationUtils.ValidateValueTypeName(model, nullValue.TypeName, expectedTypeReference.Definition.TypeKind);
                Debug.Assert(actualResolvedType != null, "This is a primitive-only codepath so actualResolvedType != null.");

                if (actualResolvedType.IsSpatial())
                {
                    ODataVersionChecker.CheckSpatialValue(version);
                }

                if (TypePromotionUtils.CanConvertTo(actualResolvedType.ToTypeReference(), expectedTypeReference))
                {
                    nullValue.TypeName = expectedTypeReference.ODataFullName();
                    return(nullValue);
                }

                throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), nullValue.TypeName));
            }

            // Only other positive case is a numeric primitive that needs to be coerced
            IEdmPrimitiveTypeReference expectedPrimitiveTypeReference = expectedTypeReference.AsPrimitiveOrNull();

            if (expectedPrimitiveTypeReference == null)
            {
                throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue));
            }

            object coercedResult = CoerceNumericType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition());

            if (coercedResult != null)
            {
                return(coercedResult);
            }

            Type actualType = primitiveValue.GetType();
            Type targetType = TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(expectedPrimitiveTypeReference));

            // If target type is assignable from actual type, we're OK
            if (targetType.IsAssignableFrom(actualType))
            {
                return(primitiveValue);
            }

            throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedPrimitiveTypeReference.ODataFullName(), primitiveValue));
        }
        /// <summary>
        /// Converts the given payload value to the type defined in a type definition.
        /// </summary>
        /// <param name="value">The given payload value.</param>
        /// <param name="edmTypeReference">The expected type reference from model.</param>
        /// <returns>The converted value of the type.</returns>
        public virtual object ConvertFromPayloadValue(object value, IEdmTypeReference edmTypeReference)
        {
            IEdmPrimitiveTypeReference primitiveTypeReference = edmTypeReference as IEdmPrimitiveTypeReference;

            Debug.Assert(primitiveTypeReference != null, "primitiveTypeReference != null");
            try
            {
                Type targetType = EdmLibraryExtensions.GetPrimitiveClrType(primitiveTypeReference.PrimitiveDefinition(), false);

                string stringValue = value as string;
                if (stringValue != null)
                {
                    return(ConvertStringValue(stringValue, targetType));
                }
                else if (value is Int32)
                {
                    return(ConvertInt32Value((int)value, targetType, primitiveTypeReference));
                }
                else if (value is Decimal)
                {
                    Decimal decimalValue = (Decimal)value;
                    if (targetType == typeof(Int64))
                    {
                        return(Convert.ToInt64(decimalValue));
                    }

                    if (targetType == typeof(Double))
                    {
                        return(Convert.ToDouble(decimalValue));
                    }

                    if (targetType == typeof(Single))
                    {
                        return(Convert.ToSingle(decimalValue));
                    }

                    if (targetType != typeof(Decimal))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDecimal(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is Double)
                {
                    Double doubleValue = (Double)value;
                    if (targetType == typeof(Single))
                    {
                        return(Convert.ToSingle(doubleValue));
                    }

                    if (targetType != typeof(Double))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDouble(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is bool)
                {
                    if (targetType != typeof(bool))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertBoolean(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTime)
                {
                    if (targetType != typeof(DateTime))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDateTime(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTimeOffset)
                {
                    if (targetType != typeof(DateTimeOffset))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDateTimeOffset(primitiveTypeReference.ODataFullName()));
                    }
                }
            }
            catch (Exception e)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(e))
                {
                    throw;
                }

                throw ReaderValidationUtils.GetPrimitiveTypeConversionException(primitiveTypeReference, e, value.ToString());
            }

            // otherwise just return the value without doing any conversion
            return(value);
        }
        internal static object ConvertValue(
            object value,
            IEdmPrimitiveTypeReference primitiveTypeReference,
            ODataMessageReaderSettings messageReaderSettings,
            ODataVersion version,
            bool validateNullValue,
            string propertyName)
        {
            Debug.Assert(primitiveTypeReference != null, "primitiveTypeReference != null");

            if (value == null)
            {
                // Only primitive type references are validated. Core model is sufficient.
                ReaderValidationUtils.ValidateNullValue(
                    EdmCoreModel.Instance,
                    primitiveTypeReference,
                    messageReaderSettings,
                    validateNullValue,
                    version,
                    propertyName);
                return(null);
            }

            try
            {
                Type targetType = EdmLibraryExtensions.GetPrimitiveClrType(primitiveTypeReference.PrimitiveDefinition(), false);

                string stringValue = value as string;
                if (stringValue != null)
                {
                    return(ConvertStringValue(stringValue, targetType));
                }
                else if (value is Int32)
                {
                    return(ConvertInt32Value((int)value, targetType, primitiveTypeReference));
                }
                else if (value is Decimal)
                {
                    Decimal decimalValue = (Decimal)value;
                    if (targetType == typeof(Int64))
                    {
                        return(Convert.ToInt64(decimalValue));
                    }

                    if (targetType == typeof(Double))
                    {
                        return(Convert.ToDouble(decimalValue));
                    }

                    if (targetType == typeof(Single))
                    {
                        return(Convert.ToSingle(decimalValue));
                    }

                    if (targetType != typeof(Decimal))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDecimal(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is Double)
                {
                    Double doubleValue = (Double)value;
                    if (targetType == typeof(Single))
                    {
                        return(Convert.ToSingle(doubleValue));
                    }

                    if (targetType != typeof(Double))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDouble(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is bool)
                {
                    if (targetType != typeof(bool))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertBoolean(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTime)
                {
                    if (targetType != typeof(DateTime))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDateTime(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTimeOffset)
                {
                    if (targetType != typeof(DateTimeOffset))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDateTimeOffset(primitiveTypeReference.ODataFullName()));
                    }
                }
            }
            catch (Exception e)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(e))
                {
                    throw;
                }

                throw ReaderValidationUtils.GetPrimitiveTypeConversionException(primitiveTypeReference, e, value.ToString());
            }

            // otherwise just return the value without doing any conversion
            return(value);
        }
        /// <summary>
        /// Converts the given JSON int value to the expected type as per OData conversion rules for JSON values.
        /// </summary>
        /// <param name="intValue">Int32 value to the converted.</param>
        /// <param name="targetType">Target type to which the int value needs to be converted.</param>
        /// <param name="primitiveTypeReference">Type reference to which the value needs to be converted.</param>
        /// <param name="usesV1ProviderBehavior">true if the conversion should use the V1 provider behavior, false if the default behavior should be used.</param>
        /// <returns>Object which is in sync with the property type (modulo the V1 exception of converting numbers to non-compatible target types).</returns>
        private static object ConvertInt32Value(int intValue, Type targetType, IEdmPrimitiveTypeReference primitiveTypeReference, bool usesV1ProviderBehavior)
        {
            if (targetType == typeof(Int16))
            {
                return(Convert.ToInt16(intValue));
            }

            if (targetType == typeof(Byte))
            {
                return(Convert.ToByte(intValue));
            }

            if (targetType == typeof(SByte))
            {
                return(Convert.ToSByte(intValue));
            }

            if (targetType == typeof(Single))
            {
                return(Convert.ToSingle(intValue));
            }

            if (targetType == typeof(Double))
            {
                return(Convert.ToDouble(intValue));
            }

            if (targetType == typeof(Decimal) ||
                targetType == typeof(Int64))
            {
                throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertInt64OrDecimal);
            }

            if (!IsV1PrimitiveType(targetType) || (targetType != typeof(Int32) && !usesV1ProviderBehavior))
            {
                throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertInt32(primitiveTypeReference.ODataFullName()));
            }

            return(intValue);
        }
        /// <summary>
        /// Reads a primitive value.
        /// </summary>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object 
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="expectedValueTypeReference">The expected type reference of the value, or null if none is available.</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:  insideJsonObjectValue == false -> none - Fails if the current node is not a JsonNodeType.PrimitiveValue
        ///                 insideJsonObjectValue == true -> JsonNodeType.Property or JsonNodeType.EndObject - the first property of the value object,
        ///                     or the second property if first was odata.type, or the end-object.
        /// Post-Condition: almost anything - the node after the primitive value.
        /// </remarks>
        private object ReadPrimitiveValue(bool insideJsonObjectValue, IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, string propertyName)
        {
            object result;

            if (expectedValueTypeReference != null && expectedValueTypeReference.IsSpatial())
            {
                result = ODataJsonReaderCoreUtils.ReadSpatialValue(
                    this.JsonReader,
                    insideJsonObjectValue,
                    this.JsonLightInputContext,
                    expectedValueTypeReference,
                    validateNullValue,
                    this.recursionDepth,
                    propertyName);
            }
            else
            {
                if (insideJsonObjectValue)
                {
                    // We manually throw JSON exception here to get a nicer error message (we expect primitive value and got object).
                    // Otherwise the ReadPrimitiveValue would fail with something like "expected primitive value but found property/end object" which is rather confusing.
                    throw new ODataException(ODataErrorStrings.JsonReaderExtensions_UnexpectedNodeDetectedWithPropertyName(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, propertyName));
                }

                result = this.JsonReader.ReadPrimitiveValue();

                if (expectedValueTypeReference != null)
                {
                    if ((expectedValueTypeReference.IsDecimal() || expectedValueTypeReference.IsInt64())
                        && result != null)
                    {
                        if ((result is string) ^ this.JsonReader.IsIeee754Compatible)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_ConflictBetweenInputFormatAndParameter(expectedValueTypeReference.ODataFullName()));
                        }
                    }

                    result = ODataJsonLightReaderUtils.ConvertValue(
                        result,
                        expectedValueTypeReference,
                        this.MessageReaderSettings,
                        validateNullValue,
                        propertyName,
                        this.Model.GetPayloadValueConverter());
                }
                else
                {
                    if (result is Decimal)
                    {
                        // convert decimal back to double to follow legacy logic when target type is not specified and IEEE754Compatible=false.
                        // we may lose precision for some range of int64 and decimal.
                        return Convert.ToDouble((Decimal)result);
                    }
                }
            }

            return result;
        }
        /// <summary>
        /// Verifies that the given <paramref name="primitiveValue"/> is or can be coerced to <paramref name="expectedTypeReference"/>, and coerces it if necessary.
        /// </summary>
        /// <param name="primitiveValue">An EDM primitive value to verify.</param>
        /// <param name="model">Model to verify against.</param>
        /// <param name="expectedTypeReference">Expected type reference.</param>
        /// <returns>Coerced version of the <paramref name="primitiveValue"/>.</returns>
        internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference)
        {
            ExceptionUtils.CheckArgumentNotNull(primitiveValue, "primitiveValue");
            ExceptionUtils.CheckArgumentNotNull(model, "model");
            ExceptionUtils.CheckArgumentNotNull(expectedTypeReference, "expectedTypeReference");

            // First deal with null literal
            ODataNullValue nullValue = primitiveValue as ODataNullValue;

            if (nullValue != null)
            {
                if (!expectedTypeReference.IsNullable)
                {
                    throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName()));
                }

                return(nullValue);
            }

            // Only other positive case is a numeric primitive that needs to be coerced
            IEdmPrimitiveTypeReference expectedPrimitiveTypeReference = expectedTypeReference.AsPrimitiveOrNull();

            if (expectedPrimitiveTypeReference == null)
            {
                throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue));
            }

            object coercedResult = CoerceNumericType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition());

            if (coercedResult != null)
            {
                return(coercedResult);
            }

            // if expectedTypeReference is set, need to coerce cast
            coercedResult = CoerceTemporalType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition());
            if (coercedResult != null)
            {
                return(coercedResult);
            }

            Type actualType = primitiveValue.GetType();
            Type targetType = TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(expectedPrimitiveTypeReference));

            // If target type is assignable from actual type, we're OK
            if (targetType.IsAssignableFrom(actualType))
            {
                return(primitiveValue);
            }

            throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedPrimitiveTypeReference.ODataFullName(), primitiveValue));
        }
 internal static ODataException GetPrimitiveTypeConversionException(IEdmPrimitiveTypeReference targetTypeReference, Exception innerException)
 {
     return(new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_CannotConvertPrimitiveValue(targetTypeReference.ODataFullName()), innerException));
 }
        /// <summary>
        /// Reads an annotation's value from the annotation value notation specified on the current element. 
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the vocabulary term from the metadata.</param>
        /// <param name="attributeValueNotationTypeReference">The type reference indicated by the name of the attribute used in attribute value notation. 
        ///   For example, if the attribute was called "string", this will be a reference to the string type.</param>
        /// <param name="attributeValueNotationAttributeName">The name of the attribute used by attribute avalue notation.</param>
        /// <param name="attributeValueNotationAttributeValue">The value of the attribute used by attribute value notation.</param>
        /// <param name="typeAttributeValue">The value of the "m:type" attribute on the annotation element.</param>
        /// <param name="positionedOnEmptyElement">true if the annotation element is empty, false otherwise.</param>
        /// <param name="model">The edm model instance.</param>
        /// <param name="messageReaderSettings">The message reader settings instance.</param>
        /// <returns>The primitive value represented on this element via attribute value notation.</returns>
        private static ODataPrimitiveValue GetValueFromAttributeValueNotation(
            IEdmTypeReference expectedTypeReference,
            IEdmPrimitiveTypeReference attributeValueNotationTypeReference,
            string attributeValueNotationAttributeName,
            string attributeValueNotationAttributeValue,
            string typeAttributeValue,
            bool positionedOnEmptyElement,
            IEdmModel model,
            ODataMessageReaderSettings messageReaderSettings)
        {
            Debug.Assert(attributeValueNotationTypeReference != null, "attributeValueNotationTypeReference != null");

            if (!positionedOnEmptyElement)
            {
                // If there is content in the body of the element, throw since it's ambiguous whether we should use the value from the attribute or the element content.
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedOnNonEmptyElement(attributeValueNotationAttributeName));
            }

            // If both m:type is present and attribute value notation is being used, they must match.
            // For example, if m:type is "Edm.Int32", but the "string" attribute is also present, we should throw.
            if (typeAttributeValue != null && !string.Equals(attributeValueNotationTypeReference.Definition.ODataFullName(), typeAttributeValue, StringComparison.Ordinal))
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedWithIncompatibleType(typeAttributeValue, attributeValueNotationAttributeName));
            }
            
            IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType(
                expectedTypeReference,
                EdmTypeKind.Primitive,
                attributeValueNotationTypeReference.Definition,
                attributeValueNotationTypeReference.ODataFullName(),
                attributeValueNotationTypeReference.Definition,
                model,
                messageReaderSettings);
            return new ODataPrimitiveValue(AtomValueUtils.ConvertStringToPrimitive(attributeValueNotationAttributeValue, targetTypeReference.AsPrimitive()));
        }
Beispiel #15
0
 internal static ODataException GetPrimitiveTypeConversionException(IEdmPrimitiveTypeReference targetTypeReference, Exception innerException)
 {
     return new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_CannotConvertPrimitiveValue(targetTypeReference.ODataFullName()), innerException);
 }
        /// <summary>
        /// Converts the given JSON value to the expected type as per OData conversion rules for JSON values.
        /// </summary>
        /// <param name="value">Value to the converted.</param>
        /// <param name="primitiveTypeReference">Type reference to which the value needs to be converted.</param>
        /// <param name="messageReaderSettings">The message reader settings used for reading.</param>
        /// <param name="version">The version of the OData protocol used for reading.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <returns>Object which is in sync with the property type (modulo the V1 exception of converting numbers to non-compatible target types).</returns>
        internal static object ConvertValue(
            object value,
            IEdmPrimitiveTypeReference primitiveTypeReference,
            ODataMessageReaderSettings messageReaderSettings,
            ODataVersion version,
            bool validateNullValue)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(primitiveTypeReference != null, "primitiveTypeReference != null");

            //// NOTE: this method was copied from WCF DS (and changed to take a type reference instead of a CLR target type)

            if (value == null)
            {
                // Only primitive type references are validated. Core model is sufficient.
                ReaderValidationUtils.ValidateNullValue(EdmCoreModel.Instance, primitiveTypeReference, messageReaderSettings, validateNullValue, version);
                return(null);
            }

            try
            {
                Type targetType = EdmLibraryExtensions.GetPrimitiveClrType(primitiveTypeReference.PrimitiveDefinition(), false);
                ODataReaderBehavior readerBehavior = messageReaderSettings.ReaderBehavior;

                string stringValue = value as string;
                if (stringValue != null)
                {
                    return(ConvertStringValue(stringValue, targetType, version));
                }
                else if (value is Int32)
                {
                    return(ConvertInt32Value((int)value, targetType, primitiveTypeReference, readerBehavior == null ? false : readerBehavior.UseV1ProviderBehavior));
                }
                else if (value is Double)
                {
                    Double doubleValue = (Double)value;
                    if (targetType == typeof(Single))
                    {
                        return(Convert.ToSingle(doubleValue));
                    }

                    if (!IsV1PrimitiveType(targetType) || (targetType != typeof(Double) && (readerBehavior == null || !readerBehavior.UseV1ProviderBehavior)))
                    {
                        throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertDouble(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is bool)
                {
                    if (targetType != typeof(bool) && (readerBehavior == null || readerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesServer))
                    {
                        throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertBoolean(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTime)
                {
                    if (targetType != typeof(DateTime) && (readerBehavior == null || readerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesServer))
                    {
                        throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertDateTime(primitiveTypeReference.ODataFullName()));
                    }
                }
                else if (value is DateTimeOffset)
                {
                    // Currently, we do not support any conversion for DateTimeOffset date type. Hence failing if the target
                    // type is not DateTimeOffset.
                    if (targetType != typeof(DateTimeOffset))
                    {
                        throw new ODataException(o.Strings.ODataJsonReaderUtils_CannotConvertDateTimeOffset(primitiveTypeReference.ODataFullName()));
                    }
                }
            }
            catch (Exception e)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(e))
                {
                    throw;
                }

                throw ReaderValidationUtils.GetPrimitiveTypeConversionException(primitiveTypeReference, e);
            }

            // otherwise just return the value without doing any conversion
            return(value);
        }
 private static object ConvertInt32Value(int intValue, Type targetType, IEdmPrimitiveTypeReference primitiveTypeReference, bool usesV1ProviderBehavior)
 {
     if (targetType == typeof(short))
     {
         return(Convert.ToInt16(intValue));
     }
     if (targetType == typeof(byte))
     {
         return(Convert.ToByte(intValue));
     }
     if (targetType == typeof(sbyte))
     {
         return(Convert.ToSByte(intValue));
     }
     if (targetType == typeof(float))
     {
         return(Convert.ToSingle(intValue));
     }
     if (targetType == typeof(double))
     {
         return(Convert.ToDouble(intValue));
     }
     if ((targetType == typeof(decimal)) || (targetType == typeof(long)))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertInt64OrDecimal);
     }
     if (!IsV1PrimitiveType(targetType) || ((targetType != typeof(int)) && !usesV1ProviderBehavior))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertInt32(primitiveTypeReference.ODataFullName()));
     }
     return(intValue);
 }
        /// <summary>
        /// Converts the given JSON int value to the expected type as per OData conversion rules for JSON values.
        /// </summary>
        /// <param name="intValue">Int32 value to the converted.</param>
        /// <param name="targetType">Target type to which the int value needs to be converted.</param>
        /// <param name="primitiveTypeReference">Type reference to which the value needs to be converted.</param>
        /// <returns>Object which is in sync with the property type.</returns>
        private static object ConvertInt32Value(int intValue, Type targetType, IEdmPrimitiveTypeReference primitiveTypeReference)
        {
            if (targetType == typeof(Int16))
            {
                return(Convert.ToInt16(intValue));
            }

            if (targetType == typeof(Byte))
            {
                return(Convert.ToByte(intValue));
            }

            if (targetType == typeof(SByte))
            {
                return(Convert.ToSByte(intValue));
            }

            if (targetType == typeof(Single))
            {
                return(Convert.ToSingle(intValue));
            }

            if (targetType == typeof(Double))
            {
                return(Convert.ToDouble(intValue));
            }

            if (targetType == typeof(Decimal))
            {
                return(Convert.ToDecimal(intValue));
            }

            if (targetType == typeof(Int64))
            {
                return(Convert.ToInt64(intValue));
            }

            if (targetType != typeof(Int32))
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertInt32(primitiveTypeReference.ODataFullName()));
            }

            return(intValue);
        }
 internal static object ConvertValue(object value, IEdmPrimitiveTypeReference primitiveTypeReference, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, bool validateNullValue)
 {
     if (value == null)
     {
         ReaderValidationUtils.ValidateNullValue(EdmCoreModel.Instance, primitiveTypeReference, messageReaderSettings, validateNullValue, version);
         return(null);
     }
     try
     {
         Type primitiveClrType = EdmLibraryExtensions.GetPrimitiveClrType(primitiveTypeReference.PrimitiveDefinition(), false);
         ODataReaderBehavior readerBehavior = messageReaderSettings.ReaderBehavior;
         string stringValue = value as string;
         if (stringValue != null)
         {
             return(ConvertStringValue(stringValue, primitiveClrType, version));
         }
         if (value is int)
         {
             return(ConvertInt32Value((int)value, primitiveClrType, primitiveTypeReference, (readerBehavior != null) && readerBehavior.UseV1ProviderBehavior));
         }
         if (value is double)
         {
             double num = (double)value;
             if (primitiveClrType == typeof(float))
             {
                 return(Convert.ToSingle(num));
             }
             if (!IsV1PrimitiveType(primitiveClrType) || ((primitiveClrType != typeof(double)) && ((readerBehavior == null) || !readerBehavior.UseV1ProviderBehavior)))
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertDouble(primitiveTypeReference.ODataFullName()));
             }
             return(value);
         }
         if (value is bool)
         {
             if ((primitiveClrType != typeof(bool)) && ((readerBehavior == null) || (readerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesServer)))
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertBoolean(primitiveTypeReference.ODataFullName()));
             }
             return(value);
         }
         if (value is DateTime)
         {
             if ((primitiveClrType != typeof(DateTime)) && ((readerBehavior == null) || (readerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesServer)))
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertDateTime(primitiveTypeReference.ODataFullName()));
             }
             return(value);
         }
         if ((value is DateTimeOffset) && (primitiveClrType != typeof(DateTimeOffset)))
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonReaderUtils_CannotConvertDateTimeOffset(primitiveTypeReference.ODataFullName()));
         }
     }
     catch (Exception exception)
     {
         if (!ExceptionUtils.IsCatchableExceptionType(exception))
         {
             throw;
         }
         throw ReaderValidationUtils.GetPrimitiveTypeConversionException(primitiveTypeReference, exception);
     }
     return(value);
 }
        /// <summary>
        /// Gets the type name based on the given odata value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="model">The model used to handle unsigned int conversions.</param>
        /// <returns>The type name for the context URI.</returns>
        private static string GetTypeNameForValue(ODataValue value, IEdmModel model)
        {
            if (value == null)
            {
                return(null);
            }

            // special identifier for null values.
            if (value.IsNullValue)
            {
                return(ODataConstants.ContextUriFragmentNull);
            }

            var typeAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>();

            if (typeAnnotation != null && !string.IsNullOrEmpty(typeAnnotation.TypeName))
            {
                return(typeAnnotation.TypeName);
            }

            var complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                return(complexValue.TypeName);
            }

            var collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                return(EdmLibraryExtensions.GetCollectionTypeFullName(collectionValue.TypeName));
            }

            var enumValue = value as ODataEnumValue;

            if (enumValue != null)
            {
                return(enumValue.TypeName);
            }

            ODataPrimitiveValue primitive = value as ODataPrimitiveValue;

            if (primitive == null)
            {
                Debug.Assert(value is ODataStreamReferenceValue, "value is ODataStreamReferenceValue");
                throw new ODataException(Strings.ODataContextUriBuilder_StreamValueMustBePropertiesOfODataEntry);
            }

            // Try convert to underlying type if the primitive value is unsigned int.
            IEdmTypeDefinitionReference typeDefinitionReference = model.ResolveUIntTypeDefinition(primitive.Value);

            if (typeDefinitionReference != null)
            {
                return(typeDefinitionReference.ODataFullName());
            }

            IEdmPrimitiveTypeReference primitiveValueTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(primitive.Value.GetType());

            return(primitiveValueTypeReference == null ? null : primitiveValueTypeReference.ODataFullName());
        }
        /// <summary>
        /// Converts the given datetime value into the allowed target types.
        /// </summary>
        /// <param name="datetimeValue">DateTime value as read by the JsonReader.</param>
        /// <param name="targetType">Target type to which the datetime value needs to be converted.</param>
        /// <param name="primitiveTypeReference">Type reference to which the value needs to be converted.</param>
        /// <param name="readerBehavior">ODataReaderBehavior instance.</param>
        /// <returns>Object which is in sync with the target type.</returns>
        private static object ConvertDateTimeValue(DateTime datetimeValue, Type targetType, IEdmPrimitiveTypeReference primitiveTypeReference, ODataReaderBehavior readerBehavior)
        {
            if (targetType == typeof(DateTimeOffset))
            {
                // If the kind of DateTime is local or UTC, that means we know the timezone information. Hence we should allow
                // conversion to DateTimeOffset - there is no dataloss or ambiguity in that conversion.
                if (datetimeValue.Kind == DateTimeKind.Local || datetimeValue.Kind == DateTimeKind.Utc)
                {
                    return(new DateTimeOffset(datetimeValue));
                }
            }

            if (targetType != typeof(DateTime) && (readerBehavior == null || readerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesServer))
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_CannotConvertDateTime(primitiveTypeReference.ODataFullName()));
            }

            return(datetimeValue);
        }