示例#1
0
 private static EdmTypeKind ComputeTargetTypeKind(IEdmTypeReference expectedTypeReference, bool forEntityValue, string payloadTypeName, EdmTypeKind payloadTypeKind, ODataMessageReaderSettings messageReaderSettings, Func<EdmTypeKind> typeKindFromPayloadFunc)
 {
     EdmTypeKind kind;
     bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadTypeKind != EdmTypeKind.None);
     if (((expectedTypeReference != null) && !flag) && (!expectedTypeReference.IsODataPrimitiveTypeKind() || !messageReaderSettings.DisablePrimitiveTypeConversion))
     {
         kind = expectedTypeReference.TypeKind();
     }
     else if (payloadTypeKind != EdmTypeKind.None)
     {
         if (!forEntityValue)
         {
             ValidationUtils.ValidateValueTypeKind(payloadTypeKind, payloadTypeName);
         }
         kind = payloadTypeKind;
     }
     else
     {
         kind = typeKindFromPayloadFunc();
     }
     if (ShouldValidatePayloadTypeKind(messageReaderSettings, expectedTypeReference, payloadTypeKind))
     {
         ValidationUtils.ValidateTypeKind(kind, expectedTypeReference.TypeKind(), payloadTypeName);
     }
     return kind;
 }
示例#2
0
        internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName,
                                                 object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext)
        {
            if (propertyKind == EdmTypeKind.Collection)
            {
                SetCollectionProperty(resource, edmProperty, propertyValue, propertyName, readContext.TimeZoneInfo);
            }
            else
            {
                if (!readContext.IsUntyped)
                {
                    if (propertyKind == EdmTypeKind.Primitive)
                    {
                        propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue,
                                                                                  GetPropertyType(resource, propertyName), readContext.TimeZoneInfo);
                    }
                    else if (propertyKind == EdmTypeKind.Enum)
                    {
                        propertyValue = EnumDeserializationHelpers.ConvertEnumValue(propertyValue,
                                                                                    GetPropertyType(resource, propertyName));
                    }
                }

                SetProperty(resource, propertyName, propertyValue);
            }
        }
        internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName,
            object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext)
        {
            if (propertyKind == EdmTypeKind.Collection)
            {
                SetCollectionProperty(resource, edmProperty, propertyValue, propertyName);
            }
            else
            {
                if (!readContext.IsUntyped)
                {
                    if (propertyKind == EdmTypeKind.Primitive)
                    {
                        propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue,
                            GetPropertyType(resource, propertyName));
                    }
                    else if (propertyKind == EdmTypeKind.Enum)
                    {
                        propertyValue = EnumDeserializationHelpers.ConvertEnumValue(propertyValue,
                            GetPropertyType(resource, propertyName));
                    }
                }

                SetProperty(resource, propertyName, propertyValue);
            }
        }
示例#4
0
        /// <summary>
        /// Parses a <paramref name="value"/> into an <see cref="IEdmExpression"/> value of the correct EDM type.
        /// </summary>
        /// <param name="edmType">The type of value.</param>
        /// <param name="value">The value to parse.</param>
        /// <returns>
        /// An IEdmExpression of type <paramref name="edmType" /> or null if the type is not supported/implemented.
        /// </returns>
        internal static IEdmExpression BuildEdmExpression(IEdmType edmType, string value)
        {
            EdmUtil.CheckArgumentNull(edmType, "edmType");
            EdmUtil.CheckArgumentNull(value, "value");

            EdmTypeKind termTypeKind = edmType.TypeKind;

            // Create expressions/constants for the corresponding types
            switch (termTypeKind)
            {
            case EdmTypeKind.Primitive:
                IEdmPrimitiveType primitiveTypeReference = (IEdmPrimitiveType)edmType;
                return(BuildEdmPrimitiveValueExp(primitiveTypeReference, value));

            case EdmTypeKind.TypeDefinition:
                IEdmTypeDefinition typeDefinitionReference = (IEdmTypeDefinition)edmType;
                return(BuildEdmPrimitiveValueExp(typeDefinitionReference.UnderlyingType(), value));

            case EdmTypeKind.Path:
                return(BuildEdmPathExp((IEdmPathType)edmType, value));

            case EdmTypeKind.Enum:
            case EdmTypeKind.Complex:
            case EdmTypeKind.Entity:
            case EdmTypeKind.Collection:
            case EdmTypeKind.EntityReference:
            case EdmTypeKind.Untyped:
            default:
                throw new NotSupportedException(Strings.EdmVocabularyAnnotations_TermTypeNotSupported(edmType.FullTypeName()));
            }
        }
示例#5
0
        private static IEdmTypeReference GetEdmTypeReference(Dictionary <Type, IEdmType> availableTypes, IEdmTypeConfiguration configuration, bool nullable)
        {
            Contract.Assert(availableTypes != null);

            if (configuration == null)
            {
                return(null);
            }

            EdmTypeKind kind = configuration.Kind;

            if (kind == EdmTypeKind.Collection)
            {
                CollectionTypeConfiguration collectionType    = (CollectionTypeConfiguration)configuration;
                EdmCollectionType           edmCollectionType =
                    new EdmCollectionType(GetEdmTypeReference(availableTypes, collectionType.ElementType, nullable));
                return(new EdmCollectionTypeReference(edmCollectionType));
            }
            else
            {
                Type configurationClrType = TypeHelper.GetUnderlyingTypeOrSelf(configuration.ClrType);

                if (!TypeHelper.IsEnum(configurationClrType))
                {
                    configurationClrType = configuration.ClrType;
                }

                IEdmType type;

                if (availableTypes.TryGetValue(configurationClrType, out type))
                {
                    if (kind == EdmTypeKind.Complex)
                    {
                        return(new EdmComplexTypeReference((IEdmComplexType)type, nullable));
                    }
                    else if (kind == EdmTypeKind.Entity)
                    {
                        return(new EdmEntityTypeReference((IEdmEntityType)type, nullable));
                    }
                    else if (kind == EdmTypeKind.Enum)
                    {
                        return(new EdmEnumTypeReference((IEdmEnumType)type, nullable));
                    }
                    else
                    {
                        throw Error.InvalidOperation(SRResources.UnsupportedEdmTypeKind, kind.ToString());
                    }
                }
                else if (configuration.Kind == EdmTypeKind.Primitive)
                {
                    PrimitiveTypeConfiguration primitiveTypeConfiguration = (PrimitiveTypeConfiguration)configuration;
                    EdmPrimitiveTypeKind       typeKind = EdmTypeBuilder.GetTypeKind(primitiveTypeConfiguration.ClrType);
                    return(EdmCoreModel.Instance.GetPrimitive(typeKind, nullable));
                }
                else
                {
                    throw Error.InvalidOperation(SRResources.NoMatchingIEdmTypeFound, configuration.FullName);
                }
            }
        }
示例#6
0
 public static bool IsOrInheritsFrom(this IEdmType thisType, IEdmType otherType)
 {
     if (thisType == null || otherType == null)
     {
         return(false);
     }
     else
     {
         if (!thisType.IsEquivalentTo(otherType))
         {
             EdmTypeKind typeKind = thisType.TypeKind;
             if (typeKind != otherType.TypeKind || typeKind != EdmTypeKind.Entity && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Row)
             {
                 return(false);
             }
             else
             {
                 return(thisType.IsOrInheritsFrom(otherType));
             }
         }
         else
         {
             return(true);
         }
     }
 }
示例#7
0
 internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation)
 {
     bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadType != null);
     if (!flag)
     {
         ValidateTypeSupported(expectedTypeReference, version);
         if (model.IsUserModel() && ((expectedTypeReference == null) || !messageReaderSettings.DisableStrictMetadataValidation))
         {
             VerifyPayloadTypeDefined(payloadTypeName, payloadType);
         }
     }
     else
     {
         ValidateTypeSupported((payloadType == null) ? null : payloadType.ToTypeReference(true), version);
     }
     if ((payloadTypeKind != EdmTypeKind.None) && (!messageReaderSettings.DisableStrictMetadataValidation || (expectedTypeReference == null)))
     {
         ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName);
     }
     serializationTypeNameAnnotation = null;
     if (!model.IsUserModel())
     {
         return null;
     }
     if ((expectedTypeReference == null) || flag)
     {
         return ResolveAndValidateTargetTypeWithNoExpectedType(expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation);
     }
     if (messageReaderSettings.DisableStrictMetadataValidation)
     {
         return ResolveAndValidateTargetTypeStrictValidationDisabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation);
     }
     return ResolveAndValidateTargetTypeStrictValidationEnabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation);
 }
        public static string ToTraceString(this IEdmType type)
        {
            EdmUtil.CheckArgumentNull <IEdmType>(type, "type");
            EdmTypeKind typeKind = type.TypeKind;

            switch (typeKind)
            {
            case EdmTypeKind.Row:
            {
                return(((IEdmRowType)type).ToTraceString());
            }

            case EdmTypeKind.Collection:
            {
                return(((IEdmCollectionType)type).ToTraceString());
            }

            case EdmTypeKind.EntityReference:
            {
                return(((IEdmEntityReferenceType)type).ToTraceString());
            }

            default:
            {
                IEdmSchemaType edmSchemaType = type as IEdmSchemaType;
                if (edmSchemaType == null)
                {
                    break;
                }
                return(edmSchemaType.ToTraceString());
            }
            }
            return("UnknownType");
        }
示例#9
0
        /// <summary>
        /// Validates that the specified type is of the requested kind.
        /// </summary>
        /// <param name="actualType">The type to validate.</param>
        /// <param name="expectedTypeKind">The type kind from the value.</param>
        /// <remarks>This override of the method will not create the type name unless it fails.</remarks>
        internal static void ValidateTypeKind(IEdmType actualType, EdmTypeKind expectedTypeKind)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(actualType != null, "actualType != null");

            ValidationUtils.ValidateTypeKind(actualType.TypeKind, expectedTypeKind, actualType.ODataFullName());
        }
示例#10
0
        private static EdmTypeKind ComputeTargetTypeKind(IEdmTypeReference expectedTypeReference, bool forEntityValue, string payloadTypeName, EdmTypeKind payloadTypeKind, ODataMessageReaderSettings messageReaderSettings, Func <EdmTypeKind> typeKindFromPayloadFunc)
        {
            EdmTypeKind kind;
            bool        flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadTypeKind != EdmTypeKind.None);

            if (((expectedTypeReference != null) && !flag) && (!expectedTypeReference.IsODataPrimitiveTypeKind() || !messageReaderSettings.DisablePrimitiveTypeConversion))
            {
                kind = expectedTypeReference.TypeKind();
            }
            else if (payloadTypeKind != EdmTypeKind.None)
            {
                if (!forEntityValue)
                {
                    ValidationUtils.ValidateValueTypeKind(payloadTypeKind, payloadTypeName);
                }
                kind = payloadTypeKind;
            }
            else
            {
                kind = typeKindFromPayloadFunc();
            }
            if (ShouldValidatePayloadTypeKind(messageReaderSettings, expectedTypeReference, payloadTypeKind))
            {
                ValidationUtils.ValidateTypeKind(kind, expectedTypeReference.TypeKind(), payloadTypeName);
            }
            return(kind);
        }
示例#11
0
        internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadType != null);

            if (!flag)
            {
                ValidateTypeSupported(expectedTypeReference, version);
                if (model.IsUserModel() && ((expectedTypeReference == null) || !messageReaderSettings.DisableStrictMetadataValidation))
                {
                    VerifyPayloadTypeDefined(payloadTypeName, payloadType);
                }
            }
            else
            {
                ValidateTypeSupported((payloadType == null) ? null : payloadType.ToTypeReference(true), version);
            }
            if ((payloadTypeKind != EdmTypeKind.None) && (!messageReaderSettings.DisableStrictMetadataValidation || (expectedTypeReference == null)))
            {
                ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName);
            }
            serializationTypeNameAnnotation = null;
            if (!model.IsUserModel())
            {
                return(null);
            }
            if ((expectedTypeReference == null) || flag)
            {
                return(ResolveAndValidateTargetTypeWithNoExpectedType(expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation));
            }
            if (messageReaderSettings.DisableStrictMetadataValidation)
            {
                return(ResolveAndValidateTargetTypeStrictValidationDisabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation));
            }
            return(ResolveAndValidateTargetTypeStrictValidationEnabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation));
        }
示例#12
0
 internal static void ValidateValueTypeKind(EdmTypeKind typeKind, string typeName)
 {
     if (((typeKind != EdmTypeKind.Primitive) && (typeKind != EdmTypeKind.Complex)) && (typeKind != EdmTypeKind.Collection))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncorrectValueTypeKind(typeName, typeKind.ToString()));
     }
 }
示例#13
0
        public static bool IsEquivalentTo(this IEdmType thisType, IEdmType otherType)
        {
            if (thisType != otherType)
            {
                if (thisType == null || otherType == null)
                {
                    return(false);
                }
                else
                {
                    if (thisType.TypeKind == otherType.TypeKind)
                    {
                        EdmTypeKind typeKind = thisType.TypeKind;
                        switch (typeKind)
                        {
                        case EdmTypeKind.None:
                        {
                            return(otherType.TypeKind == EdmTypeKind.None);
                        }

                        case EdmTypeKind.Primitive:
                        {
                            return(thisType.IsEquivalentTo((IEdmPrimitiveType)otherType));
                        }

                        case EdmTypeKind.Entity:
                        case EdmTypeKind.Complex:
                        case EdmTypeKind.Enum:
                        {
                            return(thisType.IsEquivalentTo((IEdmSchemaType)otherType));
                        }

                        case EdmTypeKind.Row:
                        {
                            return(thisType.IsEquivalentTo((IEdmRowType)otherType));
                        }

                        case EdmTypeKind.Collection:
                        {
                            return(thisType.IsEquivalentTo((IEdmCollectionType)otherType));
                        }

                        case EdmTypeKind.EntityReference:
                        {
                            return(thisType.IsEquivalentTo((IEdmEntityReferenceType)otherType));
                        }
                        }
                        throw new InvalidOperationException(Strings.UnknownEnumVal_TypeKind(thisType.TypeKind));
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            else
            {
                return(true);
            }
        }
示例#14
0
        internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider,
                                            ODataDeserializerContext readContext, out EdmTypeKind typeKind)
        {
            if (oDataValue == null)
            {
                typeKind = EdmTypeKind.None;
                return(null);
            }

            ODataComplexValue complexValue = oDataValue as ODataComplexValue;

            if (complexValue != null)
            {
                typeKind = EdmTypeKind.Complex;
                return(ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext));
            }

            ODataCollectionValue collection = oDataValue as ODataCollectionValue;

            if (collection != null)
            {
                typeKind = EdmTypeKind.Collection;
                Contract.Assert(propertyType != null, "Open collection properties are not supported.");
                return(ConvertCollectionValue(collection, propertyType, deserializerProvider, readContext));
            }

            typeKind = EdmTypeKind.Primitive;
            return(oDataValue);
        }
示例#15
0
        /// <summary>
        /// Returns true if the compared type reference is semantically equivalent to this type reference.
        /// Schema types (<see cref="IEdmSchemaType"/>) are compared by their object refs.
        /// </summary>
        /// <param name="thisType">Type reference being compared.</param>
        /// <param name="otherType">Type referenced being compared to.</param>
        /// <returns>Equivalence of the two type references.</returns>
        public static bool IsEquivalentTo(this IEdmTypeReference thisType, IEdmTypeReference otherType)
        {
            if (thisType == otherType)
            {
                return(true);
            }

            if (thisType == null || otherType == null)
            {
                return(false);
            }

            thisType  = thisType.AsActualTypeReference();
            otherType = otherType.AsActualTypeReference();

            EdmTypeKind typeKind = thisType.TypeKind();

            if (typeKind != otherType.TypeKind())
            {
                return(false);
            }

            if (typeKind == EdmTypeKind.Primitive)
            {
                return(((IEdmPrimitiveTypeReference)thisType).IsEquivalentTo((IEdmPrimitiveTypeReference)otherType));
            }
            else
            {
                return(thisType.IsNullable == otherType.IsNullable &&
                       thisType.Definition.IsEquivalentTo(otherType.Definition));
            }
        }
示例#16
0
        /// <summary>
        /// Validates a type name to ensure that it's not an empty string and resolves it against the provided <paramref name="model"/>.
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeName">The type name to validate.</param>
        /// <param name="expectedTypeKind">The expected type kind for the given type name.</param>
        /// <returns>The type with the given name and kind if a user model was available, otherwise null.</returns>
        internal static IEdmType ResolveAndValidateTypeName(IEdmModel model, string typeName, EdmTypeKind expectedTypeKind)
        {
            Debug.Assert(model != null, "model != null");

            if (typeName == null)
            {
                // if we have metadata, the type name of an entry must not be null
                if (model.IsUserModel())
                {
                    throw new ODataException(Strings.WriterValidationUtils_MissingTypeNameWithMetadata);
                }

                return null;
            }

            if (typeName.Length == 0)
            {
                throw new ODataException(Strings.ValidationUtils_TypeNameMustNotBeEmpty);
            }

            if (!model.IsUserModel())
            {
                return null;
            }

            // If we do have metadata, lookup the type and translate it to a type.
            IEdmType resolvedType = MetadataUtils.ResolveTypeNameForWrite(model, typeName);
            if (resolvedType == null)
            {
                throw new ODataException(Strings.ValidationUtils_UnrecognizedTypeName(typeName));
            }

            ValidationUtils.ValidateTypeKind(resolvedType.TypeKind, expectedTypeKind, resolvedType.ODataFullName());
            return resolvedType;
        }
示例#17
0
        /// <summary>
        /// Validates that the observed type kind is the expected type kind.
        /// </summary>
        /// <param name="actualTypeKind">The actual type kind to compare.</param>
        /// <param name="expectedTypeKind">The expected type kind to compare against.</param>
        /// <param name="expectStructuredType">This value indicates if the <paramref name="actualTypeKind"/> is expected to be complex or entity.
        /// True for complex or entity, false for non-structured type kind, null for indetermination.</param>
        /// <param name="typeName">The name of the type to use in the error.</param>
        internal static void ValidateTypeKind(EdmTypeKind actualTypeKind, EdmTypeKind expectedTypeKind, bool?expectStructuredType, string typeName)
        {
            if (expectStructuredType.HasValue && expectStructuredType.Value &&
                (expectedTypeKind.IsStructured() || expectedTypeKind == EdmTypeKind.None) &&
                actualTypeKind.IsStructured())
            {
                return;
            }

            if (expectedTypeKind != actualTypeKind)
            {
                if (typeName == null)
                {
                    throw new ODataException(Strings.ValidationUtils_IncorrectTypeKindNoTypeName(actualTypeKind.ToString(), expectedTypeKind.ToString()));
                }

                if (actualTypeKind == EdmTypeKind.TypeDefinition && expectedTypeKind == EdmTypeKind.Primitive ||
                    actualTypeKind == EdmTypeKind.Primitive && expectedTypeKind == EdmTypeKind.TypeDefinition ||
                    actualTypeKind == EdmTypeKind.Primitive && expectedTypeKind == EdmTypeKind.None)
                {
                    return;
                }

                throw new ODataException(Strings.ValidationUtils_IncorrectTypeKind(typeName, expectedTypeKind.ToString(), actualTypeKind.ToString()));
            }
        }
        internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName,
                                                 object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext)
        {
            if (propertyKind == EdmTypeKind.Collection)
            {
                SetCollectionProperty(resource, edmProperty, propertyValue, propertyName);
            }
            else
            {
                var  isUntypedProp = readContext.GetType().GetProperty("IsUntyped", BindingFlags.NonPublic | BindingFlags.Instance);
                bool isUntyped     = (bool)isUntypedProp.GetValue(readContext, null);

                //if (!readContext.IsUntyped)
                if (!isUntyped)
                {
                    if (propertyKind == EdmTypeKind.Primitive)
                    {
                        propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue,
                                                                                  GetPropertyType(resource, propertyName));
                    }
                }

                SetProperty(resource, propertyName, propertyValue);
            }
        }
示例#19
0
        /// <summary>
        /// Read the value of the __metadata property and compute the payload kind based on the type name.
        /// </summary>
        /// <remarks>This method checks whether it can determine the type kind from the type name; if we
        /// find a primitive or collection type we set the result to empty since such payloads are not supported.
        /// Otherwise we'll treat the payload as an entry since top-level complex values are not supported either.
        /// Pre-Condition:  Any                             The first node of the __metadata property value
        /// Post-Condition: Property or EndObject           This method reads the entire value of the __metadata object and positions
        ///                                                 the reader on the next property or on the EndObject node if this is the last property.
        /// </remarks>
        private void ProcessMetadataPropertyValue()
        {
            // Clear all previously detected payload kinds since when we find a top-level __metadata
            // we base our decision solely on it.
            this.detectedPayloadKinds.Clear();

            string typeName = this.ReadTypeNameFromMetadataPropertyValue();

            // NOTE: we intentionally do not use the model passed to the message reader because we want to
            //       keep the paylaod detection code independent of any model (at least for now).
            EdmTypeKind typeKind = EdmTypeKind.None;

            if (typeName != null)
            {
                MetadataUtils.ResolveTypeNameForRead(
                    EdmCoreModel.Instance,
                    /*expectedType*/ null,
                    typeName,
                    this.MessageReaderSettings.ReaderBehavior,
                    this.Version,
                    out typeKind);
            }

            // A valid top-level object with a __metadata property must not specify a primitive or collection type
            if (typeKind == EdmTypeKind.Primitive || typeKind == EdmTypeKind.Collection)
            {
                return;
            }

            Debug.Assert(typeKind == EdmTypeKind.None, "In the core model we should only be able to detect primitive and collection types.");

            // We don't support top-level complex value so the payload has to be an entry
            this.detectedPayloadKinds.Add(ODataPayloadKind.Entry);
        }
示例#20
0
 private static IEdmTypeReference ValidateMetadataType(IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue)
 {
     if (typeReferenceFromMetadata != null)
     {
         if (typeReferenceFromValue == null)
         {
             return(typeReferenceFromMetadata);
         }
         EdmTypeKind expectedTypeKind = typeReferenceFromMetadata.TypeKind();
         ValidationUtils.ValidateTypeKind(typeReferenceFromValue.Definition, expectedTypeKind);
         if (typeReferenceFromValue.IsODataPrimitiveTypeKind())
         {
             ValidationUtils.ValidateMetadataPrimitiveType(typeReferenceFromMetadata, typeReferenceFromValue);
             return(typeReferenceFromValue);
         }
         if (expectedTypeKind == EdmTypeKind.Entity)
         {
             ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)typeReferenceFromMetadata, (IEdmEntityTypeReference)typeReferenceFromValue);
             return(typeReferenceFromValue);
         }
         if (typeReferenceFromMetadata.ODataFullName() != typeReferenceFromValue.ODataFullName())
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncompatibleType(typeReferenceFromValue.ODataFullName(), typeReferenceFromMetadata.ODataFullName()));
         }
     }
     return(typeReferenceFromValue);
 }
        private static IOpenApiAny CreateStructuredTypePropertiesExample(ODataContext context, IEdmStructuredType structuredType)
        {
            OpenApiObject example = new OpenApiObject();

            IEdmEntityType entityType = structuredType as IEdmEntityType;

            // properties
            foreach (var property in structuredType.Properties())
            {
                // IOpenApiAny item;
                IEdmTypeReference propertyType = property.Type;

                IOpenApiAny item = GetTypeNameForExample(context, propertyType);

                EdmTypeKind typeKind = propertyType.TypeKind();
                if (typeKind == EdmTypeKind.Primitive && item is OpenApiString)
                {
                    OpenApiString stringAny = item as OpenApiString;
                    string        value     = stringAny.Value;
                    if (entityType != null && entityType.Key().Any(k => k.Name == property.Name))
                    {
                        value += " (identifier)";
                    }
                    if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay())
                    {
                        value += " (timestamp)";
                    }
                    item = new OpenApiString(value);
                }

                example.Add(property.Name, item);
            }

            return(example);
        }
示例#22
0
 public EdmPrimitiveType(EdmPrimitiveTypeKind kind)
 {
     this.PrimitiveKind     = kind;
     this.Namespace         = "namespace";
     this.Name              = "name";
     this.SchemaElementKind = EdmSchemaElementKind.None;
     this.TypeKind          = EdmTypeKind.None;
 }
示例#23
0
 public EdmPrimitiveType(EdmPrimitiveTypeKind kind)
 {
     this.PrimitiveKind = kind;
     this.Namespace = "namespace";
     this.Name = "name";
     this.SchemaElementKind = EdmSchemaElementKind.None;
     this.TypeKind = EdmTypeKind.None;
 }
示例#24
0
        /// <summary>
        /// Checks whether a type refers to an OData Enumeration type
        /// </summary>
        /// <param name="type">The (non-null) <see cref="IEdmType"/> to check.</param>
        /// <returns>true if the <paramref name="type"/> is an OData enumeration type; otherwise false.</returns>
        internal static bool IsODataEnumTypeKind(this IEdmType type)
        {
            ExceptionUtils.CheckArgumentNotNull(type, "type");

            EdmTypeKind typeKind = type.TypeKind;

            return(typeKind == EdmTypeKind.Enum);
        }
 public CustomEnumType(string namespaceName, string name, IEdmPrimitiveType underlyingType)
 {
     this.typeKind       = EdmTypeKind.Enum;
     this.name           = name;
     this.namespaceName  = namespaceName;
     this.isFlags        = false;
     this.underlyingType = underlyingType;
 }
 public CustomEnumType(string namespaceName, string name, EdmTypeKind typeKind)
 {
     this.typeKind       = typeKind;
     this.name           = name;
     this.namespaceName  = namespaceName;
     this.isFlags        = false;
     this.underlyingType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Int32);
 }
示例#27
0
        /// <summary>
        /// ODL callback for client type resolution
        /// </summary>
        /// <param name="expectedEdmType">The expected type for the given wire name</param>
        /// <param name="wireName">The name of the type from the payload</param>
        /// <returns>An IEdmType</returns>
        internal IEdmType ResolveWireTypeName(IEdmType expectedEdmType, string wireName)
        {
            // ODataLib should never pass an empty or null type name
            Debug.Assert(!String.IsNullOrEmpty(wireName), "!String.IsNullOrEmpty(wireName)");

            // For V3 and above, ODataLib will never call the type resolver if there is a collection
            // type specified in the wire. However, in V1/V2, since there was no collection feature
            // supported, it will call us with a collection wire name, but its okay to return null
            // in that case, since there is no collection supported. If the user writes the type
            // resolver in such a way to handle collections themselves, even then it will fail later
            // in ODataLib stating collection types are not supported in V1/V2 versions.
            if (expectedEdmType != null)
            {
                // In V1/V2, we never used to call the type resolver for primitives types.
                // Instead, we just used to look at the expected property type and try to convert
                // the value from the payload to the expected property type. In other words, we
                // used to ignore the type name on the wire for primitive properties.
                if (expectedEdmType.TypeKind == EdmTypeKind.Primitive)
                {
                    return(expectedEdmType);
                }
            }

            Type expectedType;

            if (expectedEdmType != null)
            {
                ClientTypeAnnotation expectedAnnotation = this.clientEdmModel.GetClientTypeAnnotation(expectedEdmType);
                Debug.Assert(expectedAnnotation != null, "expectedAnnotation != null");
                expectedType = expectedAnnotation.ElementType;
            }
            else
            {
                expectedType = typeof(object);
            }

            // Breaking change: we decided to validate against the resolved type if the type are not assignable.
            Type resolvedType = this.ResolveTypeFromName(wireName, expectedType);

            ClientTypeAnnotation resolvedTypeAnnotation = this.clientEdmModel.GetClientTypeAnnotation(this.clientEdmModel.GetOrCreateEdmType(resolvedType));

            Debug.Assert(resolvedTypeAnnotation != null, "result != null -- otherwise ClientType.Create returned null");

            IEdmType    clientEdmType = resolvedTypeAnnotation.EdmType;
            EdmTypeKind typeKind      = clientEdmType.TypeKind;

            if (typeKind == EdmTypeKind.Entity || typeKind == EdmTypeKind.Complex)
            {
                // If the edm type name is not present in the dictionary, add it to the map
                string edmTypeName = clientEdmType.FullName();
                if (!this.edmTypeNameMap.ContainsKey(edmTypeName))
                {
                    this.edmTypeNameMap.Add(edmTypeName, resolvedTypeAnnotation);
                }
            }

            return(clientEdmType);
        }
示例#28
0
 /// <summary>
 /// Resolves the name of a primitive, complex, entity or collection type to the respective type. Uses the semantics used be readers.
 /// Thus it can be a bit looser.
 /// </summary>
 /// <param name="model">The model to use.</param>
 /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param>
 /// <param name="typeName">The name of the type to resolve.</param>
 /// <param name="clientCustomTypeResolver">The function of client cuetom type resolver.</param>
 /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled
 /// even if the method returns null, for example for Collection types with item types which are not recognized.</param>
 /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>;
 /// or null if no such type could be found.</returns>
 internal static IEdmType ResolveTypeNameForRead(
     IEdmModel model,
     IEdmType expectedType,
     string typeName,
     Func <IEdmType, string, IEdmType> clientCustomTypeResolver,
     out EdmTypeKind typeKind)
 {
     return(ResolveTypeName(model, expectedType, typeName, clientCustomTypeResolver, out typeKind));
 }
        public void MeasuresVocabularyTypes(string termName, EdmTypeKind typeKind, string typeName)
        {
            var type = this.model.FindDeclaredType("Org.OData.Measures.V1." + termName);

            Assert.NotNull(type);

            Assert.Equal(typeKind, type.TypeKind);
            Assert.Equal(typeName, type.FullTypeName());
        }
示例#30
0
        /// <summary>
        /// Validates a type kind for a value type.
        /// </summary>
        /// <param name="typeKind">The type kind.</param>
        /// <param name="typeName">The name of the type (used for error reporting only).</param>
        internal static void ValidateValueTypeKind(EdmTypeKind typeKind, string typeName)
        {
            Debug.Assert(typeName != null, "typeName != null");

            if (typeKind != EdmTypeKind.Primitive && typeKind != EdmTypeKind.Enum && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Collection)
            {
                throw new ODataException(Strings.ValidationUtils_IncorrectValueTypeKind(typeName, typeKind.ToString()));
            }
        }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="itemTypeNameFromCollection">The item type name extracted from the collection type name.</param>
 internal CollectionWithoutExpectedTypeValidator(string itemTypeNameFromCollection)
 {
     if (itemTypeNameFromCollection != null)
     {
         this.itemTypeName = GetItemTypeFullName(itemTypeNameFromCollection);
         this.itemTypeKind = ComputeExpectedTypeKind(this.itemTypeName, out this.primitiveItemType);
         this.itemTypeDerivedFromCollectionValue = true;
     }
 }
示例#32
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="itemTypeNameFromCollection">The item type name extracted from the collection type name.</param>
 internal CollectionWithoutExpectedTypeValidator(string itemTypeNameFromCollection)
 {
     if (itemTypeNameFromCollection != null)
     {
         this.itemTypeName = GetItemTypeFullName(itemTypeNameFromCollection);
         this.itemTypeKind = ComputeExpectedTypeKind(this.itemTypeName, out this.primitiveItemType);
         this.itemTypeDerivedFromCollectionValue = true;
     }
 }
示例#33
0
        /// <summary>
        /// Validates a type kind for a value type.
        /// </summary>
        /// <param name="typeKind">The type kind.</param>
        /// <param name="typeName">The name of the type (used for error reporting only).</param>
        internal static void ValidateValueTypeKind(EdmTypeKind typeKind, string typeName)
        {
            Debug.Assert(typeName != null, "typeName != null");

            if (typeKind != EdmTypeKind.Primitive && typeKind != EdmTypeKind.Enum && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Collection)
            {
                throw new ODataException(Strings.ValidationUtils_IncorrectValueTypeKind(typeName, typeKind.ToString()));
            }
        }
示例#34
0
        public void VisitTypeReference(IEdmTypeReference reference)
        {
            EdmTypeKind edmTypeKind = reference.TypeKind();

            switch (edmTypeKind)
            {
            case EdmTypeKind.None:
            {
                this.ProcessTypeReference(reference);
                return;
            }

            case EdmTypeKind.Primitive:
            {
                this.VisitPrimitiveTypeReference(reference.AsPrimitive());
                return;
            }

            case EdmTypeKind.Entity:
            {
                this.ProcessEntityTypeReference(reference.AsEntity());
                return;
            }

            case EdmTypeKind.Complex:
            {
                this.ProcessComplexTypeReference(reference.AsComplex());
                return;
            }

            case EdmTypeKind.Row:
            {
                this.ProcessRowTypeReference(reference.AsRow());
                return;
            }

            case EdmTypeKind.Collection:
            {
                this.ProcessCollectionTypeReference(reference.AsCollection());
                return;
            }

            case EdmTypeKind.EntityReference:
            {
                this.ProcessEntityReferenceTypeReference(reference.AsEntityReference());
                return;
            }

            case EdmTypeKind.Enum:
            {
                this.ProcessEnumTypeReference(reference.AsEnum());
                return;
            }
            }
            throw new InvalidOperationException(Strings.UnknownEnumVal_TypeKind(reference.TypeKind().ToString()));
        }
示例#35
0
        internal static IEdmType ResolveTypeName(
            IEdmModel model,
            IEdmType expectedType,
            string typeName,
            Func <IEdmType, string, IEdmType> customTypeResolver,
            ODataVersion version,
            out EdmTypeKind typeKind)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(typeName != null, "typeName != null");
            IEdmType resolvedType = null;

            // Collection types should only be recognized in V3 and higher.
            string itemTypeName = EdmLibraryExtensions.GetCollectionItemTypeName(typeName);

            if (itemTypeName == null)
            {
                // Note: we require the type resolver or the model to also resolve
                //       primitive types.
                if (customTypeResolver != null && model.IsUserModel())
                {
                    resolvedType = customTypeResolver(expectedType, typeName);
                    if (resolvedType == null)
                    {
                        // If a type resolver is specified it must never return null.
                        throw new ODataException(Strings.MetadataUtils_ResolveTypeName(typeName));
                    }
                }
                else
                {
                    resolvedType = model.FindType(typeName);
                }

                typeKind = resolvedType == null ? EdmTypeKind.None : resolvedType.TypeKind;
            }
            else
            {
                // Collection
                typeKind = EdmTypeKind.Collection;
                EdmTypeKind itemTypeKind;

                IEdmType expectedItemType = null;
                if (customTypeResolver != null && expectedType != null && expectedType.TypeKind == EdmTypeKind.Collection)
                {
                    expectedItemType = ((IEdmCollectionType)expectedType).ElementType.Definition;
                }

                IEdmType itemType = ResolveTypeName(model, expectedItemType, itemTypeName, customTypeResolver, version, out itemTypeKind);
                if (itemType != null)
                {
                    resolvedType = EdmLibraryExtensions.GetCollectionType(itemType);
                }
            }

            return(resolvedType);
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="itemTypeNameFromCollection">The item type name extracted from the collection type name.</param>
        internal CollectionWithoutExpectedTypeValidator(string itemTypeNameFromCollection)
        {
            DebugUtils.CheckNoExternalCallers();

            if (itemTypeNameFromCollection != null)
            {
                this.itemTypeName = itemTypeNameFromCollection;
                this.itemTypeKind = ComputeExpectedTypeKind(this.itemTypeName, out this.primitiveItemType);
                this.itemTypeDerivedFromCollectionValue = true;
            }
        }
示例#37
0
        /// <summary>
        /// Returns true if this type kind represents a structured type.
        /// </summary>
        /// <param name="typeKind">Reference to the calling object.</param>
        /// <returns>This kind refers to a structured type.</returns>
        public static bool IsStructured(this EdmTypeKind typeKind)
        {
            switch (typeKind)
            {
            case EdmTypeKind.Entity:
            case EdmTypeKind.Complex:
                return(true);
            }

            return(false);
        }
示例#38
0
 /// <summary>
 /// Validates that the observed type kind is the expected type kind.
 /// </summary>
 /// <param name="actualTypeKind">The actual type kind.</param>
 /// <param name="expectedTypeKind">The expected type kind.</param>
 /// <param name="expectStructuredType">This value indicates if the <paramref name="actualTypeKind"/> is expected to be complex or entity.
 /// True for complex or entity, false for non-structured type kind, null for indetermination.</param>
 /// <param name="edmType">The edm type to use in the error.</param>
 /// <remarks>If expectedStructuredType is true, then expectedTypeKind could be </remarks>
 public virtual void ValidateTypeKind(EdmTypeKind actualTypeKind,
                                      EdmTypeKind expectedTypeKind,
                                      bool?expectStructuredType,
                                      IEdmType edmType)
 {
     if (settings.ThrowIfTypeConflictsWithMetadata)
     {
         ValidationUtils.ValidateTypeKind(
             actualTypeKind, expectedTypeKind, expectStructuredType, edmType == null ? null : edmType.FullTypeName());
     }
 }
示例#39
0
 internal static void SetDynamicProperty(object resource, IEdmStructuredTypeReference resourceType,
     EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmTypeReference propertyType,
     ODataDeserializerContext readContext, AssembliesResolver assembliesResolver)
 {  
     if (propertyKind == EdmTypeKind.Collection && propertyValue.GetType() != typeof(EdmComplexObjectCollection)
         && propertyValue.GetType() != typeof(EdmEnumObjectCollection))
     {
         SetDynamicCollectionProperty(resource, propertyName, propertyValue, propertyType.AsCollection(),
             resourceType.StructuredDefinition(), readContext, assembliesResolver);
     }
     else
     {
         SetDynamicProperty(resource, propertyName, propertyValue, resourceType.StructuredDefinition(),
             readContext);
     }
 }
 internal void ValidateCollectionItem(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind)
 {
     if ((collectionItemTypeKind != EdmTypeKind.Primitive) && (collectionItemTypeKind != EdmTypeKind.Complex))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_InvalidItemTypeKind(collectionItemTypeKind));
     }
     if (this.itemTypeDerivedFromCollectionValue)
     {
         collectionItemTypeName = collectionItemTypeName ?? this.itemTypeName;
         this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind);
     }
     else
     {
         if (this.itemTypeKind == EdmTypeKind.None)
         {
             this.itemTypeKind = (collectionItemTypeName == null) ? collectionItemTypeKind : ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType);
             if (collectionItemTypeName == null)
             {
                 this.itemTypeKind = collectionItemTypeKind;
                 if (this.itemTypeKind == EdmTypeKind.Primitive)
                 {
                     this.itemTypeName = "Edm.String";
                     this.primitiveItemType = EdmCoreModel.Instance.GetString(false).PrimitiveDefinition();
                 }
                 else
                 {
                     this.itemTypeName = null;
                     this.primitiveItemType = null;
                 }
             }
             else
             {
                 this.itemTypeKind = ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType);
                 this.itemTypeName = collectionItemTypeName;
             }
         }
         if ((collectionItemTypeName == null) && (collectionItemTypeKind == EdmTypeKind.Primitive))
         {
             collectionItemTypeName = "Edm.String";
         }
         this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind);
     }
 }
示例#41
0
 internal static IEdmTypeReference ResolveTypeNameForWriting(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ref string typeName, EdmTypeKind typeKindFromValue, bool isOpenPropertyType)
 {
     IEdmType type = ValidateValueTypeName(model, typeName, typeKindFromValue, isOpenPropertyType);
     IEdmTypeReference typeReferenceFromValue = type.ToTypeReference();
     if (typeReferenceFromMetadata != null)
     {
         ValidationUtils.ValidateTypeKind(typeKindFromValue, typeReferenceFromMetadata.TypeKind(), (type == null) ? null : type.ODataFullName());
     }
     typeReferenceFromValue = ValidateMetadataType(typeReferenceFromMetadata, typeReferenceFromValue);
     if ((typeKindFromValue == EdmTypeKind.Collection) && (typeReferenceFromValue != null))
     {
         typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue);
     }
     if ((typeName == null) && (typeReferenceFromValue != null))
     {
         typeName = typeReferenceFromValue.ODataFullName();
     }
     return typeReferenceFromValue;
 }
        /// <summary>
        /// Validates a type name to ensure that it's not an empty string.
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeName">The type name to validate.</param>
        /// <param name="typeKind">The expected type kind for the given type name.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>The type with the given name and kind if the model is a user model, otherwise null.</returns>
        internal static IEdmType ValidateValueTypeName(IEdmModel model, string typeName, EdmTypeKind typeKind, bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(model != null, "model != null");
            Debug.Assert(typeKind != EdmTypeKind.Entity, "This method is only for value types.");

            if (typeName == null)
            {
                // if we have metadata the type name of an entry or a complex value of an open property must not be null
                if (model.IsUserModel() && isOpenPropertyType)
                {
                    throw new ODataException(Strings.WriterValidationUtils_MissingTypeNameWithMetadata);
                }

                return null;
            }

            return ValidationUtils.ValidateValueTypeName(model, typeName, typeKind);
        }
        internal static void SetDynamicProperty(object resource, IEdmStructuredTypeReference resourceType,
            EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmTypeReference propertyType,
            ODataDeserializerContext readContext)
        {
            if (propertyKind == EdmTypeKind.Collection)
            {
                SetDynamicCollectionProperty(resource, propertyName, propertyValue, propertyType.AsCollection(),
                    resourceType.StructuredDefinition(), readContext);
            }
            else
            {
                if (propertyKind == EdmTypeKind.Enum)
                {
                    propertyValue = ConvertDynamicEnumValue(propertyValue, readContext);
                }

                SetDynamicProperty(resource, propertyName, propertyValue, resourceType.StructuredDefinition(),
                    readContext);
            }
        }
 private void ValidateCollectionItemTypeNameAndKind(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind)
 {
     if (this.itemTypeKind != collectionItemTypeKind)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeKind(collectionItemTypeKind, this.itemTypeKind));
     }
     if (this.itemTypeKind == EdmTypeKind.Primitive)
     {
         if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) == 0)
         {
             return;
         }
         if (this.primitiveItemType.IsSpatial())
         {
             EdmPrimitiveTypeKind primitiveTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(collectionItemTypeName);
             IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(primitiveTypeKind);
             if (this.itemTypeDerivedFromCollectionValue)
             {
                 if (this.primitiveItemType.IsAssignableFrom(primitiveType))
                 {
                     return;
                 }
             }
             else
             {
                 IEdmPrimitiveType commonBaseType = this.primitiveItemType.GetCommonBaseType(primitiveType);
                 if (commonBaseType != null)
                 {
                     this.primitiveItemType = commonBaseType;
                     this.itemTypeName = commonBaseType.ODataFullName();
                     return;
                 }
             }
         }
         throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName));
     }
     if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) != 0)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName));
     }
 }
示例#45
0
 private static IEdmType ResolveTypeName(IEdmModel model, IEdmType expectedType, string typeName, Func<IEdmType, string, IEdmType> customTypeResolver, ODataVersion version, out EdmTypeKind typeKind)
 {
     IEdmType collectionType = null;
     EdmTypeKind kind;
     string str = (version >= ODataVersion.V3) ? EdmLibraryExtensions.GetCollectionItemTypeName(typeName) : null;
     if (str == null)
     {
         if ((customTypeResolver != null) && model.IsUserModel())
         {
             collectionType = customTypeResolver(expectedType, typeName);
             if (collectionType == null)
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.MetadataUtils_ResolveTypeName(typeName));
             }
         }
         else
         {
             collectionType = model.FindType(typeName);
         }
         if (((version < ODataVersion.V3) && (collectionType != null)) && collectionType.IsSpatial())
         {
             collectionType = null;
         }
         typeKind = (collectionType == null) ? EdmTypeKind.None : collectionType.TypeKind;
         return collectionType;
     }
     typeKind = EdmTypeKind.Collection;
     IEdmType definition = null;
     if (((customTypeResolver != null) && (expectedType != null)) && (expectedType.TypeKind == EdmTypeKind.Collection))
     {
         definition = ((IEdmCollectionType) expectedType).ElementType.Definition;
     }
     IEdmType itemType = ResolveTypeName(model, definition, str, customTypeResolver, version, out kind);
     if (itemType != null)
     {
         collectionType = EdmLibraryExtensions.GetCollectionType(itemType);
     }
     return collectionType;
 }
        /// <summary>
        /// Resolves the payload type versus the expected type and validates that such combination is allowed when the strict validation is disabled.
        /// </summary>
        /// <param name="expectedTypeKind">The expected type kind for the value.</param>
        /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param>
        /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param>
        /// <returns>The target type reference to use for parsing the value.</returns>
        private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled(
            EdmTypeKind expectedTypeKind,
            IEdmTypeReference expectedTypeReference,
            IEdmType payloadType)
        {
            // Lax validation logic
            switch (expectedTypeKind)
            {
                case EdmTypeKind.Complex:
                    // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related 
                    // in any way. In that case we will just use the expected type because we are in lax mode. 
                    if (payloadType != null && expectedTypeKind == payloadType.TypeKind)
                    {
                        // Verify if it's a derived complex type, in all other cases simply use the expected type.
                        VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ false);
                        if (EdmLibraryExtensions.IsAssignableFrom(expectedTypeReference.AsComplex().ComplexDefinition(), (IEdmComplexType)payloadType))
                        {
                            return payloadType.ToTypeReference(/*nullable*/ true);
                        }
                    }

                    break;
                case EdmTypeKind.Entity:
                    // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related 
                    // in any way. In that case we will just use the expected type because we are in lax mode. 
                    if (payloadType != null && expectedTypeKind == payloadType.TypeKind)
                    {
                        // If the type is assignable (equal or derived) we will use the payload type, since we want to allow derived entities
                        if (EdmLibraryExtensions.IsAssignableFrom(expectedTypeReference.AsEntity().EntityDefinition(), (IEdmEntityType)payloadType))
                        {
                            IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true);
                            return payloadTypeReference;
                        }
                    }

                    break;
                case EdmTypeKind.Collection:
                    // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related 
                    // in any way. In that case we will just use the expected type because we are in lax mode. 
                    if (payloadType != null && expectedTypeKind == payloadType.TypeKind)
                    {
                        VerifyCollectionComplexItemType(expectedTypeReference, payloadType);
                    }

                    break;
                case EdmTypeKind.Enum: // enum: no validation

                    break;
                case EdmTypeKind.TypeDefinition: // type definition: no validation

                    break;
                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind));
            }

            // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal.
            return expectedTypeReference;
        }
示例#47
0
        internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider,
            ODataDeserializerContext readContext, out EdmTypeKind typeKind)
        {
            if (oDataValue == null)
            {
                typeKind = EdmTypeKind.None;
                return null;
            }

            ODataComplexValue complexValue = oDataValue as ODataComplexValue;
            if (complexValue != null)
            {
                typeKind = EdmTypeKind.Complex;
                return ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext);
            }

            ODataEnumValue enumValue = oDataValue as ODataEnumValue;
            if (enumValue != null)
            {
                typeKind = EdmTypeKind.Enum;
                return ConvertEnumValue(enumValue, ref propertyType, deserializerProvider, readContext);
            }

            ODataCollectionValue collection = oDataValue as ODataCollectionValue;
            if (collection != null)
            {
                typeKind = EdmTypeKind.Collection;
                return ConvertCollectionValue(collection, ref propertyType, deserializerProvider, readContext);
            }
            
            typeKind = EdmTypeKind.Primitive;
            return oDataValue;
        }
        /// <summary>
        /// Validates a collection item that was read to make sure it is valid (i.e., has the correct
        /// type name and type kind) with respect to the other items in the collection.
        /// </summary>
        /// <param name="collectionItemTypeName">The type name of the item from the payload.</param>
        /// <param name="collectionItemTypeKind">The type kind of the item from the payload.</param>
        internal void ValidateCollectionItem(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind)
        {
            // Only primitive and complex values are allowed in collections
            if (collectionItemTypeKind != EdmTypeKind.Primitive && collectionItemTypeKind != EdmTypeKind.Enum && collectionItemTypeKind != EdmTypeKind.Complex)
            {
                throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_InvalidItemTypeKind(collectionItemTypeKind));
            }

            if (this.itemTypeDerivedFromCollectionValue)
            {
                Debug.Assert(this.itemTypeName != null, "this.itemType != null");

                // If the collection has a type name assign missing item type names from it.
                collectionItemTypeName = collectionItemTypeName ?? this.itemTypeName;

                // If we have a type name from the collection, make sure the type names of all items match
                this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind);
            }
            else
            {
                // If we don't have a type name from the collection, store the type name and type kind of the first non-null item.
                if (this.itemTypeKind == EdmTypeKind.None)
                {
                    // Compute the kind from the specified type name if available.
                    this.itemTypeKind = collectionItemTypeName == null
                        ? collectionItemTypeKind
                        : ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType);

                    // If no payload type name is specified either default to Edm.String (for primitive type kinds) or leave the type name
                    // null (for complex items without type name)
                    if (collectionItemTypeName == null)
                    {
                        this.itemTypeKind = collectionItemTypeKind;
                        if (this.itemTypeKind == EdmTypeKind.Primitive)
                        {
                            this.itemTypeName = Metadata.EdmConstants.EdmStringTypeName;
                            this.primitiveItemType = EdmCoreModel.Instance.GetString(/*isNullable*/ false).PrimitiveDefinition();
                        }
                        else
                        {
                            this.itemTypeName = null;
                            this.primitiveItemType = null;
                        }
                    }
                    else
                    {
                        this.itemTypeKind = ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType);
                        this.itemTypeName = collectionItemTypeName;
                    }
                }

                if (collectionItemTypeName == null && collectionItemTypeKind == EdmTypeKind.Primitive)
                {
                    // Default to Edm.String if no payload type is specified and the type kind is 'Primitive'
                    collectionItemTypeName = Metadata.EdmConstants.EdmStringTypeName;
                }

                // Validate the expected and actual type names and type kinds.
                // Note that we compute the expected type kind from the expected type name and thus the payload
                // type kind (passed to this method) might be different from the computed expected type kind.
                this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind);
            }
        }
        /// <summary>
        /// Resolves the payload type if there's no expected type.
        /// </summary>
        /// <param name="expectedTypeKind">The expected type kind for the value.</param>
        /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param>
        /// <returns>The target type reference to use for parsing the value.</returns>
        private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType(
            EdmTypeKind expectedTypeKind,
            IEdmType payloadType)
        {
            // No expected type (for example an open property, but other scenarios are possible)
            // We need some type to go on. We do have a model, so we must perform metadata validation and for that we need a type.
            if (payloadType == null)
            {
                if (expectedTypeKind == EdmTypeKind.Entity)
                {
                    throw new ODataException(Strings.ReaderValidationUtils_EntryWithoutType);
                }

                return null; // supports undeclared property
            }

            // Payload types are always nullable.
            IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true);

            // Use the payload type (since we don't have any other).
            return payloadTypeReference;
        }
        /// <summary>
        /// Validate that the expected and actual type names and type kinds are compatible.
        /// </summary>
        /// <param name="collectionItemTypeName">The actual type name.</param>
        /// <param name="collectionItemTypeKind">The actual type kind.</param>
        private void ValidateCollectionItemTypeNameAndKind(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind)
        {
            // Compare the item type kinds.
            if (this.itemTypeKind != collectionItemTypeKind)
            {
                throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeKind(collectionItemTypeKind, this.itemTypeKind));
            }

            if (this.itemTypeKind == EdmTypeKind.Primitive)
            {
                Debug.Assert(this.primitiveItemType != null, "this.primitiveItemType != null");
                Debug.Assert(collectionItemTypeName != null, "collectionItemTypeName != null");

                // NOTE: we do support type inheritance for spatial primitive types; otherwise the type names have to match.
                if (!string.IsNullOrEmpty(this.itemTypeName) && this.itemTypeName.Equals(collectionItemTypeName, System.StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }

                if (this.primitiveItemType.IsSpatial())
                {
                    EdmPrimitiveTypeKind collectionItemPrimitiveKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(collectionItemTypeName);
                    IEdmPrimitiveType collectionItemPrimitiveType = EdmCoreModel.Instance.GetPrimitiveType(collectionItemPrimitiveKind);

                    if (this.itemTypeDerivedFromCollectionValue)
                    {
                        // If the collection defines an item type, the collection item type has to be assignable to it.
                        if (this.primitiveItemType.IsAssignableFrom(collectionItemPrimitiveType))
                        {
                            return;
                        }
                    }
                    else
                    {
                        // If the collection does not define an item type, the collection items must have a common base type.
                        IEdmPrimitiveType commonBaseType = EdmLibraryExtensions.GetCommonBaseType(this.primitiveItemType, collectionItemPrimitiveType);
                        if (commonBaseType != null)
                        {
                            this.primitiveItemType = commonBaseType;
                            this.itemTypeName = commonBaseType.FullTypeName();
                            return;
                        }
                    }
                }

                throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName));
            }
            else
            {
                // Since we do not support type inheritance for complex types, comparison of the type names is sufficient
                if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) != 0)
                {
                    throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName));
                }
            }
        }
        /// <summary>
        /// Resolves the payload type versus the expected type and validates that such combination is allowed.
        /// </summary>
        /// <param name="expectedTypeKind">The expected type kind for the value.</param>
        /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param>
        /// <param name="payloadTypeKind">The payload type kind, this may be the one from the type itself, or one detected without resolving the type.</param>
        /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param>
        /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param>
        /// <param name="model">The model to use.</param>
        /// <param name="messageReaderSettings">The message reader settings to use.</param>
        /// <returns>
        /// The target type reference to use for parsing the value.
        /// If there is no user specified model, this will return null.
        /// If there is a user specified model, this method never returns null.
        /// </returns>
        /// <remarks>
        /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead.
        /// </remarks>
        internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(
            EdmTypeKind expectedTypeKind,
            IEdmTypeReference expectedTypeReference,
            EdmTypeKind payloadTypeKind,
            IEdmType payloadType,
            string payloadTypeName,
            IEdmModel model,
            ODataMessageReaderSettings messageReaderSettings)
        {
            Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null");
            Debug.Assert(
                expectedTypeKind == EdmTypeKind.Enum || expectedTypeKind == EdmTypeKind.Complex || expectedTypeKind == EdmTypeKind.Entity ||
                expectedTypeKind == EdmTypeKind.Collection || expectedTypeKind == EdmTypeKind.TypeDefinition,
                "The expected type kind must be one of Enum, Complex, Entity, Collection or TypeDefinition.");
            Debug.Assert(
                payloadTypeKind == EdmTypeKind.Complex || payloadTypeKind == EdmTypeKind.Entity ||
                payloadTypeKind == EdmTypeKind.Collection || payloadTypeKind == EdmTypeKind.None ||
                payloadTypeKind == EdmTypeKind.Primitive || payloadTypeKind == EdmTypeKind.Enum ||
                payloadTypeKind == EdmTypeKind.TypeDefinition,
                "The payload type kind must be one of None, Primitive, Enum, Complex, Entity, Collection or TypeDefinition.");
            Debug.Assert(
                expectedTypeReference == null || expectedTypeReference.TypeKind() == expectedTypeKind,
                "The expected type kind must match the expected type reference if that is available.");
            Debug.Assert(
                payloadType == null || payloadType.TypeKind == payloadTypeKind,
                "The payload type kind must match the payload type if that is available.");
            Debug.Assert(payloadType == null || payloadTypeName != null, "If we have a payload type, we must have its name as well.");

            bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadType != null;
            if (!useExpectedTypeOnlyForTypeResolution)
            {
                ValidateTypeSupported(expectedTypeReference);

                // We should validate that the payload type resolved before anything else to produce reasonable error messages
                // Otherwise we might report errors which are somewhat confusing (like "Type '' is Complex but Collection was expected.").
                if (model.IsUserModel() && (expectedTypeReference == null || !messageReaderSettings.DisableStrictMetadataValidation))
                {
                    // When using a type resolver (i.e., useExpectedTypeOnlyForTypeResolution == true) then we don't have to
                    // call this method because the contract with the type resolver is to always resolve the type name and thus
                    // we will always get a defined type.
                    VerifyPayloadTypeDefined(payloadTypeName, payloadType);
                }
            }
            else
            {
                // Payload types are always nullable.
                ValidateTypeSupported(payloadType == null ? null : payloadType.ToTypeReference(/*nullable*/ true));
            }

            // In lax mode don't cross check kinds of types (we would just use the expected type) unless we expect
            // an open property of a specific kind (e.g. top level complex property for PUT requests)
            if (payloadTypeKind != EdmTypeKind.None && (!messageReaderSettings.DisableStrictMetadataValidation || expectedTypeReference == null))
            {
                // Make sure that the type kinds match.
                ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName);
            }

            if (!model.IsUserModel())
            {
                // If there's no model, it means we should not have the expected type either, and that there's no type to use,
                // no metadata validation to perform.
                Debug.Assert(expectedTypeReference == null, "If we don't have a model, we must not have expected type either.");
                return null;
            }

            if (expectedTypeReference == null || useExpectedTypeOnlyForTypeResolution)
            {
                Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here.");
                return ResolveAndValidateTargetTypeWithNoExpectedType(
                    expectedTypeKind,
                    payloadType);
            }

            if (messageReaderSettings.DisableStrictMetadataValidation)
            {
                return ResolveAndValidateTargetTypeStrictValidationDisabled(
                    expectedTypeKind,
                    expectedTypeReference,
                    payloadType);
            }

            Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here.");
            return ResolveAndValidateTargetTypeStrictValidationEnabled(
                expectedTypeKind,
                expectedTypeReference,
                payloadType);
        }
        /// <summary>
        /// Resolves and validates the payload type against the expected type and returns the target type.
        /// </summary>
        /// <param name="expectedTypeKind">The expected type kind for the value.</param>
        /// <param name="defaultPrimitivePayloadType">The default payload type if none is specified in the payload;
        /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param>
        /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param>
        /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param>
        /// <param name="model">The model to use.</param>
        /// <param name="messageReaderSettings">The message reader settings to use.</param>
        /// <param name="typeKindFromPayloadFunc">A func to compute the type kind from the payload shape if it could not be determined from the expected type or the payload type.</param>
        /// <param name="targetTypeKind">The target type kind to be used to read the payload.</param>
        /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param>
        /// <returns>
        /// The target type reference to use for parsing the value.
        /// If there is no user specified model, this will return null.
        /// If there is a user specified model, this method never returns null.
        /// </returns>
        /// <remarks>
        /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead.
        /// </remarks>
        internal static IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType(
            EdmTypeKind expectedTypeKind,
            IEdmType defaultPrimitivePayloadType,
            IEdmTypeReference expectedTypeReference,
            string payloadTypeName,
            IEdmModel model,
            ODataMessageReaderSettings messageReaderSettings,
            Func<EdmTypeKind> typeKindFromPayloadFunc,
            out EdmTypeKind targetTypeKind,
            out SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            Debug.Assert(typeKindFromPayloadFunc != null, "typeKindFromPayloadFunc != null");

            serializationTypeNameAnnotation = null;

            // What is the right behavior if both expected and actual types are specified for complex value?
            //             We decided that they have to match exactly.

            // Resolve the type name and get the payload type kind; that is the type kind of the payload
            // type if available or the expected type kind if no payload type could be resolved. Since
            // we always detect primitive and collection types the expected type for unrecognized payload
            // types is EdmTypeKind.Complex.
            EdmTypeKind payloadTypeKind;
            IEdmType payloadType = ResolvePayloadTypeName(
                model,
                expectedTypeReference,
                payloadTypeName,
                EdmTypeKind.Complex,
                messageReaderSettings.ReaderBehavior,
                out payloadTypeKind);

            // Compute the target type kind based on the expected type, the payload type kind
            // and a function to detect the target type kind from the shape of the payload.
            targetTypeKind = ComputeTargetTypeKind(
                expectedTypeReference,
                /*forEntityValue*/ expectedTypeKind == EdmTypeKind.Entity,
                payloadTypeName,
                payloadTypeKind,
                messageReaderSettings,
                typeKindFromPayloadFunc);

            // Resolve potential conflicts between payload and expected types and apply all the various behavior changing flags from settings
            IEdmTypeReference targetTypeReference;
            if (targetTypeKind == EdmTypeKind.Primitive)
            {
                targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType(
                    expectedTypeReference,
                    payloadTypeKind,
                    payloadType,
                    payloadTypeName,
                    defaultPrimitivePayloadType,
                    model,
                    messageReaderSettings);
            }
            else
            {
                targetTypeReference = ReaderValidationUtils.ResolveAndValidateNonPrimitiveTargetType(
                    targetTypeKind,
                    expectedTypeReference,
                    payloadTypeKind,
                    payloadType,
                    payloadTypeName,
                    model,
                    messageReaderSettings);

                if (targetTypeReference != null)
                {
                    serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference);
                }
            }

            if (expectedTypeKind != EdmTypeKind.None && targetTypeReference != null)
            {
                ValidationUtils.ValidateTypeKind(targetTypeKind, expectedTypeKind, payloadTypeName);
            }

            return targetTypeReference;
        }
        /// <summary>
        /// Resolves the primitive payload type versus the expected type and validates that such combination is allowed.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference, if any.</param>
        /// <param name="payloadTypeKind">The kind of the payload type, or None if the detection was not possible.</param>
        /// <param name="payloadType">The resolved payload type, or null if no payload type was specified.</param>
        /// <param name="payloadTypeName">The name of the payload type, or null if no payload type was specified.</param>
        /// <param name="defaultPayloadType">The default payload type if none is specified in the payload;
        /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param>
        /// <param name="model">The model to use.</param>
        /// <param name="messageReaderSettings">The message reader settings to use.</param>
        /// <returns>The target type reference to use for parsing the value. This method never returns null.</returns>
        internal static IEdmTypeReference ResolveAndValidatePrimitiveTargetType(
            IEdmTypeReference expectedTypeReference,
            EdmTypeKind payloadTypeKind,
            IEdmType payloadType,
            string payloadTypeName,
            IEdmType defaultPayloadType,
            IEdmModel model,
            ODataMessageReaderSettings messageReaderSettings)
        {
            Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null");
            Debug.Assert(
                payloadTypeKind == EdmTypeKind.Primitive || payloadTypeKind == EdmTypeKind.Complex ||
                payloadTypeKind == EdmTypeKind.Entity || payloadTypeKind == EdmTypeKind.Collection ||
                payloadTypeKind == EdmTypeKind.None || payloadTypeKind == EdmTypeKind.TypeDefinition,
                "The payload type kind must be one of None, Primitive, Complex, Entity, Collection or TypeDefinition.");
            Debug.Assert(
                expectedTypeReference == null || expectedTypeReference.TypeKind() == EdmTypeKind.Primitive,
                "This method only works for primitive expected type.");
            Debug.Assert(
                payloadType == null || payloadType.TypeKind == payloadTypeKind,
                "The payload type kind must match the payload type if that is available.");
            Debug.Assert(payloadType == null || payloadTypeName != null, "If we have a payload type, we must have its name as well.");

            bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadType != null;

            if (expectedTypeReference != null && !useExpectedTypeOnlyForTypeResolution)
            {
                ValidateTypeSupported(expectedTypeReference);
            }

            // Validate type kinds except for open properties or when in lax mode, but only if primitive type conversion is enabled.
            // If primitive type conversion is disabled, the type kind must match, no matter what validation mode is used.
            // The rules for primitive types are:
            // - In the strict mode the payload value must be convertible to the expected type. So the payload type must be a primitive type.
            // - In the lax mode the payload type is ignored, so its type kind is not verified in any way
            // - If the DisablePrimitiveTypeConversion == true, the lax/strict mode doesn't matter and we will read the payload value on its own.
            //     In this case we require the payload value to always be a primitive type (so type kinds must match), but it may not be convertible
            //     to the expected type, it will still be reported to the caller. 
            if (payloadTypeKind != EdmTypeKind.None && (messageReaderSettings.DisablePrimitiveTypeConversion || !messageReaderSettings.DisableStrictMetadataValidation))
            {
                // Make sure that the type kinds match.
                ValidationUtils.ValidateTypeKind(payloadTypeKind, EdmTypeKind.Primitive, payloadTypeName);
            }

            if (!model.IsUserModel())
            {
                // If there's no model, it means we should not have the expected type either, and that there's no type to use,
                // no metadata validation to perform.
                Debug.Assert(expectedTypeReference == null, "If we don't have a model, we must not have expected type either.");
                return MetadataUtils.GetNullablePayloadTypeReference(payloadType ?? defaultPayloadType);
            }

            // If the primitive type conversion is off, use the payload type always.
            // If there's no expected type or the expected type is ignored, use the payload type as well.
            if (expectedTypeReference == null || useExpectedTypeOnlyForTypeResolution || messageReaderSettings.DisablePrimitiveTypeConversion)
            {
                // If there's no payload type, use the default payload type.
                // Note that in collections the items without type should inherit the type name from the collection, in that case the expectedTypeReference
                // is never null (assuming we do have a model), so we won't get here.
                return MetadataUtils.GetNullablePayloadTypeReference(payloadType ?? defaultPayloadType);
            }

            // The server ignores the payload type when expected type is specified
            // The server is going to use lax mode everywhere so this is not an issue.
            if (messageReaderSettings.DisableStrictMetadataValidation)
            {
                // Lax validation logic
                // Always use the expected type, the payload type is ignored.
                return expectedTypeReference;
            }

            // Strict validation logic
            // We assume the expected type in the case where no payload type is specified
            // for a primitive value (in strict mode); if no expected type is available we assume Edm.String.
            if (payloadType != null)
            {
                // The payload type must be convertible to the expected type.
                // Note that we compare the type definitions, since we want to ignore nullability (the payload type doesn't specify nullability).
                if (!MetadataUtilsCommon.CanConvertPrimitiveTypeTo(
                    null /* sourceNodeOrNull */,
                    (IEdmPrimitiveType)payloadType.AsActualType(),
                    (IEdmPrimitiveType)(expectedTypeReference.Definition)))
                {
                    throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadTypeName, expectedTypeReference.ODataFullName()));
                }
            }

            // Read using the expected type. 
            // If there was a payload type we verified that it's convertible and thus we can safely read 
            // the content of the value as the expected type.
            return expectedTypeReference;
        }
        /// <summary>
        /// Resolved the payload type name to the type.
        /// </summary>
        /// <param name="model">The model to use for the resolution.</param>
        /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param>
        /// <param name="payloadTypeName">The payload type name to resolve.</param>
        /// <param name="expectedTypeKind">The default payload type kind, this is used when the resolution is not possible,
        /// but the type name is not empty. (Should be either Complex or Entity).</param>
        /// <param name="readerBehavior">Reader behavior to use for compatibility.</param>
        /// <param name="payloadTypeKind">This is set to the detected payload type kind, or None if the type was not specified.</param>
        /// <returns>The resolved type. This may be null if either no user-specified model is specified, or the type name is not recognized by the model.</returns>
        /// <remarks>The method detects the payload kind even if the model does not recognize the type. It figures out primitive and collection types always,
        /// and uses the <paramref name="expectedTypeKind"/> for the rest.</remarks>
        internal static IEdmType ResolvePayloadTypeName(
            IEdmModel model,
            IEdmTypeReference expectedTypeReference,
            string payloadTypeName,
            EdmTypeKind expectedTypeKind,
            ODataReaderBehavior readerBehavior,
            out EdmTypeKind payloadTypeKind)
        {
            if (payloadTypeName == null)
            {
                payloadTypeKind = EdmTypeKind.None;
                return null;
            }

            // Empty type names are allowed.
            if (payloadTypeName.Length == 0)
            {
                payloadTypeKind = expectedTypeKind;
                return null;
            }

            IEdmType payloadType = MetadataUtils.ResolveTypeNameForRead(
                model,
                expectedTypeReference == null ? null : expectedTypeReference.Definition,
                payloadTypeName,
                readerBehavior,
                out payloadTypeKind);
            if (payloadTypeKind == EdmTypeKind.None)
            {
                payloadTypeKind = expectedTypeKind;
            }

            return payloadType;
        }
示例#55
0
        /// <summary>
        /// Resolves the name of a primitive, complex, entity or collection type to the respective type. Uses the semantics used be readers.
        /// Thus it can be a bit looser.
        /// </summary>
        /// <param name="model">The model to use or null if no model is available.</param>
        /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param>
        /// <param name="typeName">The name of the type to resolve.</param>
        /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param>
        /// <param name="version">The version of the payload being read.</param>
        /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled
        /// even if the method returns null, for example for Collection types with item types which are not recognized.</param>
        /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>;
        /// or null if no such type could be found.</returns>
        internal static IEdmType ResolveTypeNameForRead(
            IEdmModel model,
            IEdmType expectedType,
            string typeName,
            ODataReaderBehavior readerBehavior,
            ODataVersion version,
            out EdmTypeKind typeKind)
        {
            DebugUtils.CheckNoExternalCallers();
            Func<IEdmType, string, IEdmType> customTypeResolver = readerBehavior == null ? null : readerBehavior.TypeResolver;
            Debug.Assert(
                customTypeResolver == null || readerBehavior.ApiBehaviorKind == ODataBehaviorKind.WcfDataServicesClient,
                "Custom type resolver can only be specified in WCF DS Client behavior.");

            return ResolveTypeName(model, expectedType, typeName, customTypeResolver, version, out typeKind);
        }
示例#56
0
 internal static IEdmType ResolveTypeNameForRead(IEdmModel model, IEdmType expectedType, string typeName, ODataReaderBehavior readerBehavior, ODataVersion version, out EdmTypeKind typeKind)
 {
     Func<IEdmType, string, IEdmType> customTypeResolver = (readerBehavior == null) ? null : readerBehavior.TypeResolver;
     return ResolveTypeName(model, expectedType, typeName, customTypeResolver, version, out typeKind);
 }
        internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider,
            ODataDeserializerContext readContext, out EdmTypeKind typeKind)
        {
            if (oDataValue == null)
            {
                typeKind = EdmTypeKind.None;
                return null;
            }

            ODataComplexValue complexValue = oDataValue as ODataComplexValue;
            if (complexValue != null)
            {
                typeKind = EdmTypeKind.Complex;
                return ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext);
            }

            ODataCollectionValue collection = oDataValue as ODataCollectionValue;
            if (collection != null)
            {
                typeKind = EdmTypeKind.Collection;
                Contract.Assert(propertyType != null, "Open collection properties are not supported.");
                return ConvertCollectionValue(collection, propertyType, deserializerProvider, readContext);
            }

            typeKind = EdmTypeKind.Primitive;
            return oDataValue;
        }
        /// <summary>
        /// Determines if the expect value type and the current settings mandate us to validate type kinds of payload values.
        /// </summary>
        /// <param name="messageReaderSettings">The message reader settings.</param>
        /// <param name="expectedValueTypeReference">The expected type reference for the value infered from the model.</param>
        /// <param name="payloadTypeKind">The type kind of the payload value.</param>
        /// <returns>true if the payload value kind must be verified, false otherwise.</returns>
        /// <remarks>This method deals with the strict versus lax behavior, as well as with the behavior when primitive type conversion is disabled.</remarks>
        private static bool ShouldValidatePayloadTypeKind(ODataMessageReaderSettings messageReaderSettings, IEdmTypeReference expectedValueTypeReference, EdmTypeKind payloadTypeKind)
        {
            // If we have a type resolver, we always use the type returned by the resolver
            // and use the expected type only for the resolution.
            bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadTypeKind != EdmTypeKind.None;

            // Type kind validation must happen when
            // - In strict mode
            // - Target type is primitive and primitive type conversion is disabled
            // In lax mode we don't want to validate type kinds, but the DisablePrimitiveTypeConversion overrides the lax mode behavior.
            // If there's no expected type, then there's nothing to validate against (open property).
            return expectedValueTypeReference != null &&
                (!messageReaderSettings.DisableStrictMetadataValidation ||
                useExpectedTypeOnlyForTypeResolution ||
                (expectedValueTypeReference.IsODataPrimitiveTypeKind() && messageReaderSettings.DisablePrimitiveTypeConversion));
        }
        /// <summary>
        /// Resolves the payload type versus the expected type and validates that such combination is allowed when strict validation is enabled.
        /// </summary>
        /// <param name="expectedTypeKind">The expected type kind for the value.</param>
        /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param>
        /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param>
        /// <returns>The target type reference to use for parsing the value.</returns>
        private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled(
            EdmTypeKind expectedTypeKind,
            IEdmTypeReference expectedTypeReference,
            IEdmType payloadType)
        {
            // Strict validation logic
            switch (expectedTypeKind)
            {
                case EdmTypeKind.Complex:
                    if (payloadType != null)
                    {
                        // The payload type must be compatible to the expected type.
                        VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ true);

                        // Use the payload type
                        return payloadType.ToTypeReference(/*nullable*/ true);
                    }

                    break;
                case EdmTypeKind.Entity:
                    if (payloadType != null)
                    {
                        // The payload type must be assignable to the expected type.
                        IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true);
                        ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)expectedTypeReference, (IEdmEntityTypeReference)payloadTypeReference);

                        // Use the payload type
                        return payloadTypeReference;
                    }

                    break;
                case EdmTypeKind.Enum:
                    if (payloadType != null && string.CompareOrdinal(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()) != 0)
                    {
                        throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()));
                    }

                    break;
                case EdmTypeKind.Collection:
                    // The type must be exactly equal - note that we intentionally ignore nullability of the items here, since the payload type
                    // can't specify that.
                    if (payloadType != null && !payloadType.IsElementTypeEquivalentTo(expectedTypeReference.Definition))
                    {
                        VerifyCollectionComplexItemType(expectedTypeReference, payloadType);

                        throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()));
                    }

                    break;
                case EdmTypeKind.TypeDefinition:
                    if (payloadType != null && !expectedTypeReference.Definition.IsAssignableFrom(payloadType))
                    {
                        throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()));
                    }

                    break;
                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind));
            }

            // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal.
            return expectedTypeReference;
        }
示例#60
0
        /// <summary>
        /// Resolves the name of a primitive, complex, entity or collection type to the respective type.
        /// </summary>
        /// <param name="model">The model to use or null if no model is available.</param>
        /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param>
        /// <param name="typeName">The name of the type to resolve.</param>
        /// <param name="customTypeResolver">Custom type resolver to use, if null the model is used directly.</param>
        /// <param name="version">The version to use when resolving the type name.</param>
        /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled
        /// even if the method returns null, for example for Collection types with item types which are not recognized.</param>
        /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>;
        /// or null if no such type could be found.</returns>
        private static IEdmType ResolveTypeName(
            IEdmModel model,
            IEdmType expectedType,
            string typeName,
            Func<IEdmType, string, IEdmType> customTypeResolver,
            ODataVersion version,
            out EdmTypeKind typeKind)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(typeName != null, "typeName != null");
            IEdmType resolvedType = null;

            // Collection types should only be recognized in V3 and higher.
            string itemTypeName = version >= ODataVersion.V3 ? EdmLibraryExtensions.GetCollectionItemTypeName(typeName) : null;
            if (itemTypeName == null)
            {
                // Note: we require the type resolver or the model to also resolve
                //       primitive types.
                if (customTypeResolver != null && model.IsUserModel())
                {
                    resolvedType = customTypeResolver(expectedType, typeName);
                    if (resolvedType == null)
                    {
                        // If a type resolver is specified it must never return null.
                        throw new ODataException(Strings.MetadataUtils_ResolveTypeName(typeName));
                    }
                }
                else
                {
                    resolvedType = model.FindType(typeName);
                }

                // Spatial types are only recognized in V3 and higher.
                if (version < ODataVersion.V3 && resolvedType != null && resolvedType.IsSpatial())
                {
                    resolvedType = null;
                }

                typeKind = resolvedType == null ? EdmTypeKind.None : resolvedType.TypeKind;
            }
            else
            {
                // Collection
                typeKind = EdmTypeKind.Collection;
                EdmTypeKind itemTypeKind;

                IEdmType expectedItemType = null;
                if (customTypeResolver != null && expectedType != null && expectedType.TypeKind == EdmTypeKind.Collection)
                {
                    expectedItemType = ((IEdmCollectionType)expectedType).ElementType.Definition;
                }

                IEdmType itemType = ResolveTypeName(model, expectedItemType, itemTypeName, customTypeResolver, version, out itemTypeKind);
                if (itemType != null)
                {
                    resolvedType = EdmLibraryExtensions.GetCollectionType(itemType);
                }
            }

            return resolvedType;
        }