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)); }
/// <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); }
/// <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> /// 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)); } }
/// <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()); }
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); }
/// <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> /// 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); }
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; }
/// <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); }
/// <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; }
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); }
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)); }
internal static void ValidateTypeKind(IEdmType actualType, EdmTypeKind expectedTypeKind) { ValidateTypeKind(actualType.TypeKind, expectedTypeKind, actualType.ODataFullName()); }
/// <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); }
/// <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); }
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; }
/// <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); }
/// <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); }