Beispiel #1
0
 private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName)
 {
     IEdmStructuredType type2 = type as IEdmStructuredType;
     IEdmProperty property = (type2 == null) ? null : type2.FindProperty(propertyName);
     if (property != null)
     {
         IEdmTypeReference typeReference = property.Type;
         if (typeReference.IsNonEntityODataCollectionTypeKind())
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName()));
         }
         if (typeReference.IsStream())
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName()));
         }
         if (typeReference.IsSpatial())
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName()));
         }
         return property.Type;
     }
     if ((type != null) && !type.IsOpenType())
     {
         throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName()));
     }
     return null;
 }
        /// <summary>
        /// Resolves the given type if a client type resolver is available.
        /// </summary>
        /// <param name="typeToResolve">Type to resolve.</param>
        /// <returns>The resolved type.</returns>
        private IEdmType ResolveType(IEdmType typeToResolve)
        {
            Debug.Assert(typeToResolve != null, "typeToResolve != null");
            Debug.Assert(this.model != null, "model != null");
            Debug.Assert(this.readerBehavior != null, "readerBehavior != null");

            Func <IEdmType, string, IEdmType> customTypeResolver = this.readerBehavior.TypeResolver;

            if (customTypeResolver == null)
            {
                return(typeToResolve);
            }

            Debug.Assert(this.readerBehavior.ApiBehaviorKind == ODataBehaviorKind.WcfDataServicesClient, "Custom type resolver can only be specified in WCF DS Client behavior.");
            EdmTypeKind typeKind;

            // MetadataUtils.ResolveTypeName() does not allow entity collection types however both operationImport.ReturnType and operationParameter.Type can be of entity collection types.
            // We don't want to relax MetadataUtils.ResolveTypeName() since the rest of ODL only allows primitive and complex collection types and is currently relying on the method to
            // enforce this.  So if typeToResolve is an entity collection type, we will resolve the item type and reconstruct the collection type from the resolved item type.
            IEdmCollectionType collectionTypeToResolve = typeToResolve as IEdmCollectionType;

            if (collectionTypeToResolve != null && collectionTypeToResolve.ElementType.IsEntity())
            {
                IEdmTypeReference itemTypeReferenceToResolve = collectionTypeToResolve.ElementType;
                IEdmType          resolvedItemType           = MetadataUtils.ResolveTypeName(this.model, null /*expectedType*/, itemTypeReferenceToResolve.FullName(), customTypeResolver, this.version, out typeKind);
                return(new EdmCollectionType(resolvedItemType.ToTypeReference(itemTypeReferenceToResolve.IsNullable)));
            }

            return(MetadataUtils.ResolveTypeName(this.model, null /*expectedType*/, typeToResolve.ODataFullName(), customTypeResolver, this.version, out typeKind));
        }
Beispiel #3
0
        /// <summary>
        /// Resolve a type name against the provided <paramref name="model"/>. If no type name is given we either throw (if a type name on the value is required, e.g., on entries)
        /// or infer the type from the model (if it is a user model).
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param>
        /// <param name="typeName">The type name to be resolved.</param>
        /// <param name="typeKindFromValue">The expected type kind of the resolved type.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>A type for the <paramref name="typeName"/> or null if no metadata is available.</returns>
        internal static IEdmTypeReference ResolveTypeNameForWriting(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ref string typeName, EdmTypeKind typeKindFromValue, bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(model != null, "model != null");
            Debug.Assert(
                typeKindFromValue == EdmTypeKind.Complex || typeKindFromValue == EdmTypeKind.Collection,
                "Only complex or collection types are supported by this method. This method assumes that the types in question don't support inheritance.");

            IEdmType          typeFromValue          = WriterValidationUtils.ValidateValueTypeName(model, typeName, typeKindFromValue, isOpenPropertyType);
            IEdmTypeReference typeReferenceFromValue = typeFromValue.ToTypeReference();

            if (typeReferenceFromMetadata != null)
            {
                ValidationUtils.ValidateTypeKind(
                    typeKindFromValue,
                    typeReferenceFromMetadata.TypeKind(),
                    typeFromValue == null ? null : typeFromValue.ODataFullName());
            }

            typeReferenceFromValue = ValidateMetadataType(typeReferenceFromMetadata, typeReferenceFromValue);

            if (typeKindFromValue == EdmTypeKind.Collection && typeReferenceFromValue != null)
            {
                // validate that the collection type represents a valid Collection type (e.g., is unordered).
                typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue);
            }

            // derive the type name from the metadata if available
            if (typeName == null && typeReferenceFromValue != null)
            {
                typeName = typeReferenceFromValue.ODataFullName();
            }

            return(typeReferenceFromValue);
        }
Beispiel #4
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());
        }
Beispiel #5
0
 /// <summary>
 /// Check whether the parent and child are properly related types
 /// </summary>
 /// <param name="parentType">the parent type</param>
 /// <param name="childType">the child type</param>
 /// <exception cref="ODataException">Throws if the two types are not related.</exception>
 public static void CheckRelatedTo(IEdmType parentType, IEdmType childType)
 {
     if (!IsRelatedTo(parentType, childType))
     {
         // If the parentType is an open property, parentType will be null and can't have an ODataFullName.
         string parentTypeName = (parentType != null) ? parentType.ODataFullName() : "<null>";
         throw new ODataException(OData.Core.Strings.MetadataBinder_HierarchyNotFollowed(childType.FullTypeName(), parentTypeName));
     }
 }
Beispiel #6
0
 /// <summary>
 /// Check whether the parent and child are properly related types
 /// </summary>
 /// <param name="parentType">the parent type</param>
 /// <param name="childType">the child type</param>
 /// <exception cref="ODataException">Throws if the two types are not related.</exception>
 public static void CheckRelatedTo(IEdmType parentType, IEdmType childType)
 {
     if (!IsRelatedTo(parentType, childType))
     {
         // If the parentType is an open property, parentType will be null and can't have an ODataFullName.
         string parentTypeName = (parentType != null) ? parentType.ODataFullName() : "<null>";
         throw new ODataException(OData.Core.Strings.MetadataBinder_HierarchyNotFollowed(childType.FullTypeName(), parentTypeName));
     }
 }
Beispiel #7
0
        /// <summary>
        /// Check whether the parent and child are properly related types
        /// </summary>
        /// <param name="parentType">the parent type</param>
        /// <param name="childType">the child type</param>
        /// <exception cref="ODataException">Throws if the two types are not related.</exception>
        public static void CheckRelatedTo(IEdmType parentType, IEdmType childType)
        {
            IEdmEntityType childEntityType = childType as IEdmEntityType;

            if (!childEntityType.IsOrInheritsFrom(parentType) && !parentType.IsOrInheritsFrom(childEntityType))
            {
                // If the parentType is an open property, parentType will be null and can't have an ODataFullName.
                string parentTypeName = (parentType != null) ? parentType.ODataFullName() : "<null>";
                throw new ODataException(OData.Strings.MetadataBinder_HierarchyNotFollowed(childEntityType.FullName(), parentTypeName));
            }
        }
        /// <summary>
        /// Translate a TypeSegment
        /// </summary>
        /// <param name="segment">the segment to Translate</param>
        /// <returns>Defined by the implementer</returns>
        public override string Translate(TypeSegment segment)
        {
            Debug.Assert(segment != null, "segment != null");
            IEdmType           type           = segment.EdmType;
            IEdmCollectionType collectionType = type as IEdmCollectionType;

            if (collectionType != null)
            {
                type = collectionType.ElementType.Definition;
            }

            return("/" + type.ODataFullName());
        }
Beispiel #9
0
        public static bool AllHaveEqualReturnTypeAndAttributes(this IList <IEdmFunctionImport> functionImports)
        {
            Debug.Assert(functionImports != null, "functionImports != null");

            if (!functionImports.Any())
            {
                return(true);
            }

            IEdmType firstReturnType    = functionImports[0].ReturnType == null ? null : functionImports[0].ReturnType.Definition;
            bool     firstComposability = functionImports[0].IsComposable;
            bool     firstSideEffecting = functionImports[0].IsSideEffecting;

            foreach (IEdmFunctionImport f in functionImports)
            {
                if (f.IsComposable != firstComposability)
                {
                    return(false);
                }

                if (f.IsSideEffecting != firstSideEffecting)
                {
                    return(false);
                }

                if (firstReturnType != null)
                {
                    if (f.ReturnType.Definition.ODataFullName() != firstReturnType.ODataFullName())
                    {
                        return(false);
                    }
                }
                else
                {
                    if (f.ReturnType != null)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            switch (expectedTypeKind)
            {
            case EdmTypeKind.Entity:
            {
                if (payloadType == null)
                {
                    break;
                }
                IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true);
                ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)expectedTypeReference, (IEdmEntityTypeReference)targetTypeReference);
                serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference);
                return(targetTypeReference);
            }

            case EdmTypeKind.Complex:
                if (payloadType != null)
                {
                    VerifyComplexType(expectedTypeReference, payloadType, true);
                }
                break;

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

            default:
                throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind));
            }
            serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference);
            return(expectedTypeReference);
        }
Beispiel #11
0
        /// <summary>
        /// Returns the type of the property on the specified type.
        /// </summary>
        /// <param name="type">The type to look for the property on.</param>
        /// <param name="propertyName">The name of the property to look for.</param>
        /// <returns>The type of the property specified.</returns>
        private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName)
        {
            Debug.Assert(propertyName != null, "propertyName != null");

            IEdmStructuredType structuredType = type as IEdmStructuredType;
            IEdmProperty       property       = structuredType == null ? null : structuredType.FindProperty(propertyName);

            if (property != null)
            {
                IEdmTypeReference propertyType = property.Type;
                if (propertyType.IsNonEntityCollectionType())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }

                if (propertyType.IsStream())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }

                if (propertyType.IsSpatial())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName()));
                }

                return(property.Type);
            }

            if (type != null && !type.IsOpenType())
            {
                throw new ODataException(ODataErrorStrings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName()));
            }

            return(null);
        }
        /// <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());
        }
        /// <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;
        }
        /// <summary>
        /// Resolves the given type if a client type resolver is available.
        /// </summary>
        /// <param name="typeToResolve">Type to resolve.</param>
        /// <returns>The resolved type.</returns>
        private IEdmType ResolveType(IEdmType typeToResolve)
        {
            Debug.Assert(typeToResolve != null, "typeToResolve != null");
            Debug.Assert(this.model != null, "model != null");
            Debug.Assert(this.readerBehavior != null, "readerBehavior != null");

            Func<IEdmType, string, IEdmType> customTypeResolver = this.readerBehavior.TypeResolver;
            if (customTypeResolver == null)
            {
                return typeToResolve;
            }

            Debug.Assert(this.readerBehavior.ApiBehaviorKind == ODataBehaviorKind.WcfDataServicesClient, "Custom type resolver can only be specified in WCF DS Client behavior.");
            EdmTypeKind typeKind;

            // MetadataUtils.ResolveTypeName() does not allow entity collection types however both operationImport.ReturnType and operationParameter.Type can be of entity collection types.
            // We don't want to relax MetadataUtils.ResolveTypeName() since the rest of ODL only allows primitive and complex collection types and is currently relying on the method to
            // enforce this.  So if typeToResolve is an entity collection type, we will resolve the item type and reconstruct the collection type from the resolved item type.
            IEdmCollectionType collectionTypeToResolve = typeToResolve as IEdmCollectionType;
            if (collectionTypeToResolve != null && collectionTypeToResolve.ElementType.IsEntity())
            {
                IEdmTypeReference itemTypeReferenceToResolve = collectionTypeToResolve.ElementType;
                IEdmType resolvedItemType = MetadataUtils.ResolveTypeName(this.model, null /*expectedType*/, itemTypeReferenceToResolve.FullName(), customTypeResolver, out typeKind);
                return new EdmCollectionType(resolvedItemType.ToTypeReference(itemTypeReferenceToResolve.IsNullable));
            }

            return MetadataUtils.ResolveTypeName(this.model, null /*expectedType*/, typeToResolve.ODataFullName(), customTypeResolver, out typeKind);
        }
Beispiel #15
0
        private bool TryCreateTypeNameSegment(ODataPathSegment previous, string identifier, string parenthesisExpression, IEdmType targetEdmType)
        {
            if (previous.TargetEdmType == null || targetEdmType == null)
            {
                return false;
            }

            // if the new type segment prevents any results from possibly being returned, then short-circuit and throw a 404.
            IEdmType previousEdmType = previous.TargetEdmType;
            Debug.Assert(previousEdmType != null, "previous.TargetEdmType != null");

            if (previousEdmType.TypeKind == EdmTypeKind.Collection)
            {
                previousEdmType = ((IEdmCollectionType)previousEdmType).ElementType.Definition;
            }

            if (!targetEdmType.IsOrInheritsFrom(previousEdmType) && !previousEdmType.IsOrInheritsFrom(targetEdmType))
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_InvalidTypeIdentifier_UnrelatedType(targetEdmType.ODataFullName(), previousEdmType.ODataFullName()));
            }

            // We want the type of the type segment to be a collection if the previous segment was a collection
            IEdmType actualTypeOfTheTypeSegment = targetEdmType;

            if (previous.EdmType.TypeKind == EdmTypeKind.Collection)
            {
                // creating a new collection type here because the type in the request is just the item type, there is no user-provided collection type.
                var actualEntityTypeOfTheTypeSegment = actualTypeOfTheTypeSegment as IEdmEntityType;
                if (actualEntityTypeOfTheTypeSegment != null)
                {
                    actualTypeOfTheTypeSegment = new EdmCollectionType(new EdmEntityTypeReference(actualEntityTypeOfTheTypeSegment, false));
                }
                else
                {
                    throw new ODataException(Strings.PathParser_TypeCastOnlyAllowedAfterEntityCollection(identifier));
                }
            }

            var typeNameSegment = (ODataPathSegment)new TypeSegment(actualTypeOfTheTypeSegment, previous.TargetEdmNavigationSource)
            {
                Identifier = identifier,
                TargetKind = previous.TargetKind,
                SingleResult = previous.SingleResult,
                TargetEdmType = targetEdmType
            };

            this.parsedSegments.Add(typeNameSegment);

            // Key expressions are allowed on Type segments
            this.TryBindKeyFromParentheses(parenthesisExpression);

            return true;
        }
Beispiel #16
0
        /// <summary>
        /// Parse from levelsOption token to LevelsClause.
        /// Negative value would be treated as max.
        /// </summary>
        /// <param name="levelsOption">The levelsOption for current expand.</param>
        /// <param name="sourceType">The type of current level navigation source.</param>
        /// <param name="property">Navigation property for current expand.</param>
        /// <returns>The LevelsClause parsed, null if levelsOption is null</returns>
        private LevelsClause ParseLevels(long? levelsOption, IEdmType sourceType, IEdmNavigationProperty property)
        {
            if (!levelsOption.HasValue)
            {
                return null;
            }

            IEdmType relatedType = property.ToEntityType();

            if (sourceType != null && relatedType != null && !UriEdmHelpers.IsRelatedTo(sourceType, relatedType))
            {
                throw new ODataException(ODataErrorStrings.ExpandItemBinder_LevelsNotAllowedOnIncompatibleRelatedType(property.Name, relatedType.ODataFullName(), sourceType.ODataFullName()));
            }

            return new LevelsClause(levelsOption.Value < 0, levelsOption.Value);
        }
Beispiel #17
0
        /// <summary>
        /// Returns the type of the property on the specified type.
        /// </summary>
        /// <param name="type">The type to look for the property on.</param>
        /// <param name="propertyName">The name of the property to look for.</param>
        /// <returns>The type of the property specified.</returns>
        private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName)
        {
            Debug.Assert(propertyName != null, "propertyName != null");

            IEdmStructuredType structuredType = type as IEdmStructuredType;
            IEdmProperty property = structuredType == null ? null : structuredType.FindProperty(propertyName);

            if (property != null)
            {
                IEdmTypeReference propertyType = property.Type;
                if (propertyType.IsNonEntityODataCollectionTypeKind())
                {
                    throw new ODataException(o.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }
                
                if (propertyType.IsStream())
                {
                    throw new ODataException(o.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }
                
                if (propertyType.IsSpatial())
                {
                    throw new ODataException(o.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName()));
                }
                
                return property.Type;
            }

            if (type != null && !type.IsOpenType())
            {
                throw new ODataException(o.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName()));
            }

            return null;
        }
Beispiel #18
0
        private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName)
        {
            IEdmStructuredType type2    = type as IEdmStructuredType;
            IEdmProperty       property = (type2 == null) ? null : type2.FindProperty(propertyName);

            if (property != null)
            {
                IEdmTypeReference typeReference = property.Type;
                if (typeReference.IsNonEntityODataCollectionTypeKind())
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }
                if (typeReference.IsStream())
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }
                if (typeReference.IsSpatial())
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName()));
                }
                return(property.Type);
            }
            if ((type != null) && !type.IsOpenType())
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName()));
            }
            return(null);
        }
Beispiel #19
0
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            List <EpmSourcePathSegment> list     = new List <EpmSourcePathSegment>();
            EpmSourcePathSegment        root     = this.Root;
            EpmSourcePathSegment        segment2 = null;
            IEdmType actualPropertyType          = epmInfo.ActualPropertyType;

            string[] strArray = epmInfo.Attribute.SourcePath.Split(new char[] { '/' });
            int      length   = strArray.Length;

            for (int i = 0; i < length; i++)
            {
                string propertyName = strArray[i];
                if (propertyName.Length == 0)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }
                IEdmTypeReference propertyType = GetPropertyType(actualPropertyType, propertyName);
                IEdmType          type2        = (propertyType == null) ? null : propertyType.Definition;
                if ((type2 == null) && (i < (length - 1)))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, actualPropertyType.ODataFullName()));
                }
                actualPropertyType = type2;
                segment2           = root.SubProperties.SingleOrDefault <EpmSourcePathSegment>(e => e.PropertyName == propertyName);
                if (segment2 != null)
                {
                    root = segment2;
                }
                else
                {
                    EpmSourcePathSegment item = new EpmSourcePathSegment(propertyName);
                    root.SubProperties.Add(item);
                    root = item;
                }
                list.Add(root);
            }
            if ((actualPropertyType != null) && !actualPropertyType.IsODataPrimitiveTypeKind())
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(root.PropertyName));
            }
            if (segment2 != null)
            {
                if (segment2.EpmInfo.DefiningTypesAreEqual(epmInfo))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }
                this.epmTargetTree.Remove(segment2.EpmInfo);
            }
            epmInfo.SetPropertyValuePath(list.ToArray());
            root.EpmInfo = epmInfo;
            this.epmTargetTree.Add(epmInfo);
        }
        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>
        /// Parse from levelsOption token to LevelsClause.
        /// Negative value would be treated as max.
        /// </summary>
        /// <param name="levelsOption">The levelsOption for current expand.</param>
        /// <param name="sourceType">The type of current level navigation source.</param>
        /// <param name="property">Navigation property for current expand.</param>
        /// <returns>The LevelsClause parsed, null if levelsOption is null</returns>
        private LevelsClause ParseLevels(long?levelsOption, IEdmType sourceType, IEdmNavigationProperty property)
        {
            if (!levelsOption.HasValue)
            {
                return(null);
            }

            IEdmType relatedType = property.ToEntityType();

            if (sourceType != null && relatedType != null && !UriEdmHelpers.IsRelatedTo(sourceType, relatedType))
            {
                throw new ODataException(ODataErrorStrings.ExpandItemBinder_LevelsNotAllowedOnIncompatibleRelatedType(property.Name, relatedType.ODataFullName(), sourceType.ODataFullName()));
            }

            return(new LevelsClause(levelsOption.Value < 0, levelsOption.Value));
        }
Beispiel #22
0
 internal static void ValidateTypeKind(IEdmType actualType, EdmTypeKind expectedTypeKind)
 {
     ValidateTypeKind(actualType.TypeKind, expectedTypeKind, actualType.ODataFullName());
 }
Beispiel #23
0
        /// <summary>
        /// Adds a path to the source and target tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/>
        /// </summary>
        /// <param name="epmInfo">EnitityPropertyMappingInfo holding the source path</param>
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            DebugUtils.CheckNoExternalCallers();

            List <EpmSourcePathSegment> pathToCurrentSegment = new List <EpmSourcePathSegment>();
            EpmSourcePathSegment        currentSourceSegment = this.Root;
            EpmSourcePathSegment        foundSourceSegment   = null;
            IEdmType currentType = epmInfo.ActualPropertyType;

            Debug.Assert(!string.IsNullOrEmpty(epmInfo.Attribute.SourcePath), "Invalid source path");
            string[] propertyPath = epmInfo.Attribute.SourcePath.Split('/');

            int propertyPathLength = propertyPath.Length;

            Debug.Assert(propertyPathLength > 0, "Must have been validated during EntityPropertyMappingAttribute construction");
            for (int sourcePropertyIndex = 0; sourcePropertyIndex < propertyPathLength; sourcePropertyIndex++)
            {
                string propertyName = propertyPath[sourcePropertyIndex];

                if (propertyName.Length == 0)
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }

                IEdmTypeReference nextPropertyTypeReference = GetPropertyType(currentType, propertyName);
                IEdmType          nextPropertyType          = nextPropertyTypeReference == null ? null : nextPropertyTypeReference.Definition;

                // If we don't find a property type this is an open property; check whether this is the last segment in the path
                // since otherwise this would not be an open primitive property and only open primitive properties are allowed.
                if (nextPropertyType == null && sourcePropertyIndex < propertyPathLength - 1)
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, currentType.ODataFullName()));
                }

                currentType        = nextPropertyType;
                foundSourceSegment = currentSourceSegment.SubProperties.SingleOrDefault(e => e.PropertyName == propertyName);
                if (foundSourceSegment != null)
                {
                    currentSourceSegment = foundSourceSegment;
                }
                else
                {
                    EpmSourcePathSegment newSourceSegment = new EpmSourcePathSegment(propertyName);
                    currentSourceSegment.SubProperties.Add(newSourceSegment);
                    currentSourceSegment = newSourceSegment;
                }

                pathToCurrentSegment.Add(currentSourceSegment);
            }

            // The last segment is the one being mapped from by the user specified attribute.
            // It must be a primitive type - we don't allow mappings of anything else than primitive properties directly.
            // Note that we can only verify this for non-open properties, for open properties we must assume it's a primitive type
            // and we will make this check later during serialization again when we actually have the value of the property.
            if (currentType != null)
            {
                if (!currentType.IsODataPrimitiveTypeKind())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_EndsWithNonPrimitiveType(currentSourceSegment.PropertyName));
                }
            }

            Debug.Assert(foundSourceSegment == null || foundSourceSegment.EpmInfo != null, "Can't have a leaf node in the tree without EpmInfo.");

            // Two EpmAttributes with same PropertyName in the same type, this could be a result of inheritance
            if (foundSourceSegment != null)
            {
                Debug.Assert(object.ReferenceEquals(foundSourceSegment, currentSourceSegment), "currentSourceSegment variable should have been updated already to foundSourceSegment");

                // Check for duplicates on the same entity type
                Debug.Assert(foundSourceSegment.SubProperties.Count == 0, "If non-leaf, it means we allowed complex type to be a leaf node");
                if (foundSourceSegment.EpmInfo.DefiningTypesAreEqual(epmInfo))
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }

                // In case of inheritance, we need to remove the node from target tree which was mapped to base type property
                this.epmTargetTree.Remove(foundSourceSegment.EpmInfo);
            }

            epmInfo.SetPropertyValuePath(pathToCurrentSegment.ToArray());
            currentSourceSegment.EpmInfo = epmInfo;

            this.epmTargetTree.Add(epmInfo);
        }
Beispiel #24
0
        /// <summary>
        /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified,
        /// derive the type from the model type (if available).
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param>
        /// <param name="typeName">The type name to be resolved.</param>
        /// <param name="typeKindFromValue">The expected type kind of the resolved type.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>A type for the <paramref name="typeName"/> or null if no type name is specified and no metadata is available.</returns>
        private static IEdmTypeReference ResolveAndValidateTypeFromNameAndMetadata(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, string typeName, EdmTypeKind typeKindFromValue, bool isOpenPropertyType)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(
                typeKindFromValue == EdmTypeKind.Complex || typeKindFromValue == EdmTypeKind.Collection || typeKindFromValue == EdmTypeKind.Enum,
                "Only complex or collection or enum types are supported by this method. This method assumes that the types in question don't support inheritance.");

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

            // starting from enum type, we want to skip validation (but still let the above makes sure open type's enum value has .TypeName)
            if (typeKindFromValue == EdmTypeKind.Enum)
            {
                return(null);
            }

            IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, typeKindFromValue);

            if (typeReferenceFromMetadata != null)
            {
                ValidationUtils.ValidateTypeKind(typeKindFromValue, typeReferenceFromMetadata.TypeKind(), typeFromValue == null ? null : typeFromValue.ODataFullName());
            }

            IEdmTypeReference typeReferenceFromValue = ValidateMetadataType(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference());

            if (typeKindFromValue == EdmTypeKind.Collection && typeReferenceFromValue != null)
            {
                // update nullability from metadata
                if (typeReferenceFromMetadata != null)
                {
                    typeReferenceFromValue = typeReferenceFromMetadata;
                }

                // validate that the collection type represents a valid Collection type (e.g., is unordered).
                typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue);
            }

            return(typeReferenceFromValue);
        }
Beispiel #25
0
        private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            switch (expectedTypeKind)
            {
                case EdmTypeKind.Entity:
                {
                    if (payloadType == null)
                    {
                        break;
                    }
                    IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true);
                    ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference) expectedTypeReference, (IEdmEntityTypeReference) targetTypeReference);
                    serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference);
                    return targetTypeReference;
                }
                case EdmTypeKind.Complex:
                    if (payloadType != null)
                    {
                        VerifyComplexType(expectedTypeReference, payloadType, true);
                    }
                    break;

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

                default:
                    throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind));
            }
            serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference);
            return expectedTypeReference;
        }
Beispiel #26
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);
        }
Beispiel #27
0
 internal static void ValidateTypeKind(IEdmType actualType, EdmTypeKind expectedTypeKind)
 {
     ValidateTypeKind(actualType.TypeKind, expectedTypeKind, actualType.ODataFullName());
 }
Beispiel #28
0
        /// <summary>
        /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified,
        /// derive the type from the model type (if available).
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param>
        /// <param name="typeName">The type name to be resolved.</param>
        /// <param name="typeKindFromValue">The expected type kind of the resolved type.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>A type for the <paramref name="typeName"/> or null if no type name is specified and no metadata is available.</returns>
        private static IEdmTypeReference ResolveAndValidateTypeFromNameAndMetadata(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, string typeName, EdmTypeKind typeKindFromValue, bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(model != null, "model != null");
            Debug.Assert(
                typeKindFromValue == EdmTypeKind.Complex || typeKindFromValue == EdmTypeKind.Collection,
                "Only complex or collection types are supported by this method. This method assumes that the types in question don't support inheritance.");

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

            IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, typeKindFromValue);

            if (typeReferenceFromMetadata != null)
            {
                ValidationUtils.ValidateTypeKind(typeKindFromValue, typeReferenceFromMetadata.TypeKind(), typeFromValue == null ? null : typeFromValue.ODataFullName());
            }

            IEdmTypeReference typeReferenceFromValue = ValidateMetadataType(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference());

            if (typeKindFromValue == EdmTypeKind.Collection && typeReferenceFromValue != null)
            {
                // validate that the collection type represents a valid Collection type (e.g., is unordered).
                typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue);
            }

            return(typeReferenceFromValue);
        }