private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (((payloadType == null) || (expectedTypeKind != payloadType.TypeKind)) || !expectedTypeReference.AsEntity().EntityDefinition().IsAssignableFrom(((IEdmEntityType)payloadType))) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return(targetTypeReference); } case EdmTypeKind.Complex: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyComplexType(expectedTypeReference, payloadType, false); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return(expectedTypeReference); }
/// <summary> /// Constructor which used when the nested resource info is a undeclared property in model. /// </summary> /// <param name="nestedResourceInfo">The nested resource info to report.</param> /// <param name="nestedProperty">The nested property for which the nested resource info will be reported.</param> /// <param name="nestedResourceType">The resource type of the nested resource info.</param> /// <param name="isExpanded">true if the nested resource info is expanded.</param> private ODataJsonLightReaderNestedResourceInfo(ODataNestedResourceInfo nestedResourceInfo, IEdmProperty nestedProperty, IEdmType nestedResourceType, bool isExpanded) : base(nestedProperty) { Debug.Assert(nestedResourceInfo != null, "nestedResourceInfo != null"); Debug.Assert(nestedResourceType != null || nestedProperty != null, "nestedResourceType and nestedProperty are both null"); this.nestedResourceInfo = nestedResourceInfo; // We get the nullablity from the nestedProperty if it exists otherwise we consider the resource to be nullable if only the nestedResourceType is specified. bool resourceTypeNullable = true; if (nestedProperty != null && nestedProperty.Type != null) { resourceTypeNullable = nestedProperty.Type.IsNullable; } IEdmType nestedType = nestedResourceType; // We get the resource type from the nestedProperty if not specified. if (nestedProperty != null && nestedType == null) { nestedType = nestedProperty.Type.Definition; } NestedResourceTypeReference = nestedType.ToTypeReference(resourceTypeNullable); this.hasValue = isExpanded; }
/// <summary> /// Parses an <paramref name="orderBy "/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="orderBy">String representation of the orderby expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the orderby clause refers to.</param> /// <param name="navigationSource">NavigationSource that the elements are from.</param> /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns> private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy"); // Get the syntactic representation of the orderby expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.OrderByLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); OrderByClause orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens); return(orderByClause); }
/// <summary> /// Parses a <paramref name="filter"/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="filter">String representation of the filter expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the filter clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns> private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(filter, "filter"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); QueryToken filterToken = expressionParser.ParseFilter(filter); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); FilterBinder filterBinder = new FilterBinder(binder.Bind, state); FilterClause boundNode = filterBinder.BindFilter(filterToken); return(boundNode); }
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)); }
/// <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> /// 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"); if (clientCustomTypeResolver == null) { return(typeToResolve); } 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(), clientCustomTypeResolver, out typeKind); return(new EdmCollectionType(resolvedItemType.ToTypeReference(itemTypeReferenceToResolve.IsNullable))); } return(MetadataUtils.ResolveTypeName(this.model, null /*expectedType*/, typeToResolve.FullTypeName(), clientCustomTypeResolver, 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> /// Verifies that the given <paramref name="primitiveValue"/> is or can be coerced to <paramref name="expectedTypeReference"/>, and coerces it if necessary. /// </summary> /// <param name="primitiveValue">An EDM primitive value to verify.</param> /// <param name="model">Model to verify against.</param> /// <param name="expectedTypeReference">Expected type reference.</param> /// <param name="version">The version to use for reading.</param> /// <returns>Coerced version of the <paramref name="primitiveValue"/>.</returns> internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(primitiveValue, "primitiveValue"); ExceptionUtils.CheckArgumentNotNull(model, "model"); ExceptionUtils.CheckArgumentNotNull(expectedTypeReference, "expectedTypeReference"); // First deal with null literal ODataUriNullValue nullValue = primitiveValue as ODataUriNullValue; if (nullValue != null) { if (!expectedTypeReference.IsNullable) { throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName())); } IEdmType actualResolvedType = ValidationUtils.ValidateValueTypeName(model, nullValue.TypeName, expectedTypeReference.Definition.TypeKind); Debug.Assert(actualResolvedType != null, "This is a primitive-only codepath so actualResolvedType != null."); if (actualResolvedType.IsSpatial()) { ODataVersionChecker.CheckSpatialValue(version); } if (TypePromotionUtils.CanConvertTo(actualResolvedType.ToTypeReference(), expectedTypeReference)) { nullValue.TypeName = expectedTypeReference.ODataFullName(); return(nullValue); } throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), nullValue.TypeName)); } // Only other positive case is a numeric primitive that needs to be coerced IEdmPrimitiveTypeReference expectedPrimitiveTypeReference = expectedTypeReference.AsPrimitiveOrNull(); if (expectedPrimitiveTypeReference == null) { throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue)); } object coercedResult = CoerceNumericType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition()); if (coercedResult != null) { return(coercedResult); } Type actualType = primitiveValue.GetType(); Type targetType = TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(expectedPrimitiveTypeReference)); // If target type is assignable from actual type, we're OK if (targetType.IsAssignableFrom(actualType)) { return(primitiveValue); } throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedPrimitiveTypeReference.ODataFullName(), primitiveValue)); }
private static IEdmTypeReference GetNullablePayloadTypeReference(IEdmType payloadType) { if (payloadType != null) { return(payloadType.ToTypeReference(true)); } return(null); }
internal static IEdmCollectionType GetCollectionType(IEdmType itemType) { if (!itemType.IsODataPrimitiveTypeKind() && !itemType.IsODataComplexTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EdmLibraryExtensions_CollectionItemCanBeOnlyPrimitiveOrComplex); } return(new EdmCollectionType(itemType.ToTypeReference())); }
private static IEdmTypeReference GetNullablePayloadTypeReference(IEdmType payloadType) { if (payloadType != null) { return payloadType.ToTypeReference(true); } return null; }
/// <summary>Helper method to get a type by its name.</summary> /// <param name="model">The model.</param> /// <param name="fullName">The name of the type to find. For the namespace the namespace of the model is used.</param> /// <param name="nullable">true if the type reference should be nullable; otherwise false.</param> /// <returns>The type found.</returns> public static IEdmTypeReference ResolveTypeReference(this IEdmModel model, string fullName, bool nullable) { IEdmType type = ResolveType(model, fullName); ExceptionUtilities.Assert(type != null, "type != null"); return(type.ToTypeReference(nullable)); }
/// <summary> /// Gets or adds the expected type annotation. /// </summary> /// <param name="payloadElement">The payload element to get or add the annotation to.</param> /// <returns>The expected type annotation to use.</returns> public static ExpectedTypeODataPayloadElementAnnotation AddExpectedTypeAnnotation(this ODataPayloadElement payloadElement, IEdmType expectedType) { Debug.Assert(payloadElement != null, "payloadElement != null"); var expectedTypeAnnotation = payloadElement.GetAnnotation <ExpectedTypeODataPayloadElementAnnotation>(); if (expectedTypeAnnotation == null) { expectedTypeAnnotation = new ExpectedTypeODataPayloadElementAnnotation(); payloadElement.SetAnnotation(expectedTypeAnnotation); } expectedTypeAnnotation.EdmExpectedType = expectedType.ToTypeReference(); return(expectedTypeAnnotation); }
private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType(EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { serializationTypeNameAnnotation = null; if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_EntryWithoutType); } throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_ValueWithoutType); } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return(targetTypeReference); }
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); }
internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull<object>(primitiveValue, "primitiveValue"); ExceptionUtils.CheckArgumentNotNull<IEdmModel>(model, "model"); ExceptionUtils.CheckArgumentNotNull<IEdmTypeReference>(expectedTypeReference, "expectedTypeReference"); ODataUriNullValue value2 = primitiveValue as ODataUriNullValue; if (value2 != null) { if (!expectedTypeReference.IsNullable) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName())); } IEdmType type = ValidationUtils.ValidateValueTypeName(model, value2.TypeName, expectedTypeReference.Definition.TypeKind); if (type.IsSpatial()) { ODataVersionChecker.CheckSpatialValue(version); } if (!TypePromotionUtils.CanConvertTo(type.ToTypeReference(), expectedTypeReference)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralNullTypeVerificationFailure(expectedTypeReference.ODataFullName(), value2.TypeName)); } value2.TypeName = expectedTypeReference.ODataFullName(); return value2; } IEdmPrimitiveTypeReference reference = expectedTypeReference.AsPrimitiveOrNull(); if (reference == null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue)); } object obj2 = CoerceNumericType(primitiveValue, reference.PrimitiveDefinition()); if (obj2 != null) { return obj2; } Type c = primitiveValue.GetType(); if (!TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(reference)).IsAssignableFrom(c)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(reference.ODataFullName(), primitiveValue)); } return primitiveValue; }
/// <summary> /// Parses an <paramref name="apply"/> clause on the given <paramref name="elementType"/>, binding /// the text into a metadata-bound or dynamic properties to be applied using the provided model. /// </summary> /// <param name="apply">String representation of the apply expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the apply clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns> private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(apply, "apply"); // Get the syntactic representation of the apply expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var applyTokens = expressionParser.ParseApply(apply); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); ApplyBinder applyBinder = new ApplyBinder(binder.Bind, state); ApplyClause boundNode = applyBinder.BindApply(applyTokens); return(boundNode); }
/// <summary> /// Resolve a resource type name /// </summary> /// <param name="model">The model to use.</param> /// <param name="expectedType">The type inferred from the model or null if the model is not a user model.</param> /// <param name="typeName">Name of the type to resolve.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for primitive value</returns> internal static IEdmStructuredType ResolveAndValidateTypeFromTypeName(IEdmModel model, IEdmStructuredType expectedType, string typeName, IWriterValidator writerValidator) { if (typeName == null && expectedType != null) { return(expectedType); } // TODO: Clean up handling of expected types/sets during writing IEdmType typeFromResource = ResolveAndValidateTypeName(model, typeName, EdmTypeKind.None, /* expectStructuredType */ true, writerValidator); IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue( expectedType.ToTypeReference(), typeFromResource == null ? null : typeFromResource.ToTypeReference(), writerValidator); if (typeReferenceFromValue != null && typeReferenceFromValue.IsUntyped()) { return(new EdmUntypedStructuredType()); } return(typeReferenceFromValue == null ? null : typeReferenceFromValue.ToStructuredType()); }
/// <summary> /// Parses a <paramref name="query"/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="query">String representation of the filter expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the filter clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns> internal static ExpressionClause ParseExpressionImplementation(string query, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(query, "query"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit); QueryToken expressionToken = expressionParser.ParseFilter(query); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); FilterBinder filterBinder = new FilterBinder(binder.Bind, state); ExpressionClause boundNode = filterBinder.BindProperyExpression(expressionToken); return(boundNode); }
/// <summary> /// Parses a <paramref name="orderBy "/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="orderBy">String representation of the orderby expression.</param> /// <param name="elementType">Type that the orderby clause refers to.</param> /// <param name="entitySet">EntitySet that the elements beign filtered are from.</param> /// <returns>A <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns> private OrderByClause ParseOrderByImplementation(string orderBy, IEdmType elementType, IEdmEntitySet entitySet) { ExceptionUtils.CheckArgumentNotNull(this.configuration.Model, "model"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(this.Settings.OrderByLimit); var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy); // Bind it to metadata BindingState state = new BindingState(this.configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), entitySet); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); OrderByClause orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens); return(orderByClause); }
/// <summary> /// Parses a <paramref name="filter"/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided. /// </summary> /// <param name="filter">String representation of the filter expression.</param> /// <param name="elementType">Type that the filter clause refers to.</param> /// <param name="entitySet">EntitySet that the elements beign filtered are from.</param> /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns> private FilterClause ParseFilterImplementation(string filter, IEdmType elementType, IEdmEntitySet entitySet) { ExceptionUtils.CheckArgumentNotNull(this.configuration, "this.configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(filter, "filter"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(this.Settings.FilterLimit); QueryToken filterToken = expressionParser.ParseFilter(filter); // Bind it to metadata BindingState state = new BindingState(this.configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), entitySet); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); FilterBinder filterBinder = new FilterBinder(binder.Bind, state); FilterClause boundNode = filterBinder.BindFilter(filterToken); return(boundNode); }
/// <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="resourceValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open (dynamic) property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="resourceValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForResourceValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataResourceValue resourceValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); Debug.Assert(resourceValue != null, "resourceValue != null"); var typeName = resourceValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); // It's ok to use "EdmTypeKind.Complex" because the validation will check "IsStructured()". IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Complex, true, writerValidator); if (typeReferenceFromMetadata != null) { // It's ok to use "EdmTypeKind.Complex" because the parameter "expectStructuredType" is set to "true". writerValidator.ValidateTypeKind(EdmTypeKind.Complex, typeReferenceFromMetadata.TypeKind(), true, typeFromValue); } return(ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator)); }
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 IEdmCollectionType implementation with the given IEdmTypeReference as element type. /// </summary> /// <param name="itemType">IEdmTypeReference instance which is the element type.</param> /// <returns>An <see cref="IEdmCollectionType"/> instance using the <paramref name="itemType"/> as Collection item type.</returns> internal static IEdmCollectionType GetCollectionType(IEdmType itemType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(itemType != null, "itemType != null"); IEdmTypeReference itemTypeReference; if (itemType.IsODataPrimitiveTypeKind() || itemType.IsODataComplexTypeKind()) { itemTypeReference = itemType.ToTypeReference(); } else { throw new ODataException(Strings.EdmLibraryExtensions_CollectionItemCanBeOnlyPrimitiveOrComplex); } return new EdmCollectionType(itemTypeReference); }
/// <summary> /// Sets the expected base entity type for the top-level entity set. /// </summary> /// <param name="entitySetInstance">The entity set instance to set the expected set for.</param> /// <param name="entitySet">The entity set the entities belong to.</param> /// <param name="baseEntityType">The base entity type to set as the expected base entity type.</param> /// <returns>The <paramref name="entitySetInstance"/> after its expected type was set.</returns> public static EntitySetInstance ExpectedEntityType(this EntitySetInstance entitySetInstance, IEdmType baseEntityType, IEdmEntitySet entitySet = null, bool nullable = false) { return(entitySetInstance.ExpectedEntityType(baseEntityType.ToTypeReference(nullable), entitySet)); }
/// <summary> /// Verifies that in case of collection types, the item type is valid. /// </summary> /// <param name="expectedTypeReference">The expected type reference.</param> /// <param name="payloadType">The payload type.</param> /// <remarks> /// This method verifies that item type is compatible with expected type. /// </remarks> private static void VerifyCollectionComplexItemType(IEdmTypeReference expectedTypeReference, IEdmType payloadType) { Debug.Assert(expectedTypeReference != null, "expectedTypeReference != null"); Debug.Assert(payloadType != null, "payloadType != null"); Debug.Assert(expectedTypeReference.IsNonEntityCollectionType(), "This method only works on atomic collections."); Debug.Assert(payloadType.IsNonEntityCollectionType(), "This method only works on atomic collections."); IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(expectedTypeReference); IEdmTypeReference expectedItemTypeReference = collectionTypeReference.GetCollectionItemType(); if (expectedItemTypeReference != null && expectedItemTypeReference.IsODataComplexTypeKind()) { IEdmCollectionTypeReference payloadCollectionTypeReference = ValidationUtils.ValidateCollectionType(payloadType.ToTypeReference()); IEdmTypeReference payloadItemTypeReference = payloadCollectionTypeReference.GetCollectionItemType(); if (payloadItemTypeReference != null && payloadItemTypeReference.IsODataComplexTypeKind()) { // Note that this method is called from both strict and lax code paths, so we must not fail if the types are not related. VerifyComplexType(expectedItemTypeReference, payloadItemTypeReference.Definition, /* failIfNotRelated */ false); } } }
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> /// Determines if a segment is a complex type. /// </summary> /// <param name="instance">Segment to be checked.</param> /// <param name="parentType">The type of the parent segment.</param> /// <returns>True if segment represents a complex type and false otherwise.</returns> private static Boolean IsDerivedComplexType(NavigationPropertyToken instance, IEdmType parentType) { IEdmProperty property = BindProperty(parentType.ToTypeReference(), instance.Name); return property.Type.IsODataComplexTypeKind(); }
/// <summary> /// Parses a <paramref name="filter"/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="filter">String representation of the filter expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the filter clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns> private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(filter, "filter"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); QueryToken filterToken = expressionParser.ParseFilter(filter); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); FilterBinder filterBinder = new FilterBinder(binder.Bind, state); FilterClause boundNode = filterBinder.BindFilter(filterToken); return boundNode; }
/// <summary> /// Convert to collection type reference from element type definition /// </summary> /// <param name="elementDefinition">The element type definiton</param> /// <returns>The collection type reference</returns> public static IEdmCollectionTypeReference ToCollectionTypeReference(this IEdmType elementDefinition) { var elementTypeReference = elementDefinition.ToTypeReference(); return(elementTypeReference.ToCollectionTypeReference()); }
private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (((payloadType == null) || (expectedTypeKind != payloadType.TypeKind)) || !expectedTypeReference.AsEntity().EntityDefinition().IsAssignableFrom(((IEdmEntityType) payloadType))) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return targetTypeReference; } case EdmTypeKind.Complex: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyComplexType(expectedTypeReference, payloadType, false); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return expectedTypeReference; }
/// <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; }
private static void VerifyCollectionComplexItemType(IEdmTypeReference expectedTypeReference, IEdmType payloadType) { IEdmTypeReference collectionItemType = ValidationUtils.ValidateCollectionType(expectedTypeReference).GetCollectionItemType(); if ((collectionItemType != null) && collectionItemType.IsODataComplexTypeKind()) { IEdmTypeReference typeReference = ValidationUtils.ValidateCollectionType(payloadType.ToTypeReference()).GetCollectionItemType(); if ((typeReference != null) && typeReference.IsODataComplexTypeKind()) { VerifyComplexType(collectionItemType, typeReference.Definition, false); } } }
/// <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; }
/// <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> /// 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> /// Sets the expected property type for the top-level property. /// </summary> /// <param name="property">The property instance to set the expected type for.</param> /// <param name="dataType">The type to set as the expected property type.</param> /// <returns>The <paramref name="property"/> after its expected type was set.</returns> public static PropertyInstance ExpectedPropertyType(this PropertyInstance property, IEdmType dataType, bool nullable = false) { ExceptionUtilities.CheckArgumentNotNull(property, "property"); ODataPayloadElementExtensions.AddExpectedTypeAnnotation(property).EdmExpectedType = dataType.ToTypeReference(nullable); return(property); }
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); }
/// <summary> /// Sets the expected item type for the top-level collection. /// </summary> /// <typeparam name="T">The acutal collection type, i.e., a primitive or a complex collection type.</typeparam> /// <param name="collection">The collection instance to set the expected item type for.</param> /// <param name="dataType">The type to set as the expected item type.</param> /// <returns>The <paramref name="collection"/> after its expected type was set.</returns> public static T ExpectedCollectionItemType <T>(this T collection, IEdmType dataType, bool nullable = true) where T : ODataPayloadElementCollection { ExceptionUtilities.CheckArgumentNotNull(collection, "collection"); AddExpectedTypeAnnotation(collection).EdmExpectedType = dataType.ToTypeReference(nullable); return(collection); }
/// <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="collectionValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="collectionValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForCollectionValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataCollectionValue collectionValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); var typeName = collectionValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Collection, false, writerValidator); if (typeReferenceFromMetadata != null) { writerValidator.ValidateTypeKind(EdmTypeKind.Collection, typeReferenceFromMetadata.TypeKind(), false, typeFromValue); } IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator); if (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); }
/// <summary> /// Gets the nullable type reference for a payload type; if the payload type is null, uses Edm.String. /// </summary> /// <param name="payloadType">The payload type to get the type reference for.</param> /// <returns>The nullable <see cref="IEdmTypeReference"/> for the <paramref name="payloadType"/>.</returns> internal static IEdmTypeReference GetNullablePayloadTypeReference(IEdmType payloadType) { return(payloadType == null ? null : payloadType.ToTypeReference(true)); }
/// <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> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</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.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType( EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here."); serializationTypeNameAnnotation = null; // 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); } throw new ODataException(Strings.ReaderValidationUtils_ValueWithoutType); } // Payload types are always nullable. IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, payloadTypeReference); // Use the payload type (since we don't have any other). return payloadTypeReference; }
/// <summary> /// Gets the nullable type reference for a payload type; if the payload type is null, uses Edm.String. /// </summary> /// <param name="payloadType">The payload type to get the type reference for.</param> /// <returns>The nullable <see cref="IEdmTypeReference"/> for the <paramref name="payloadType"/>.</returns> internal static IEdmTypeReference GetNullablePayloadTypeReference(IEdmType payloadType) { return payloadType == null ? null : payloadType.ToTypeReference(true); }
private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType(EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { serializationTypeNameAnnotation = null; if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_EntryWithoutType); } throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_ValueWithoutType); } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return targetTypeReference; }
/// <summary> /// Parses an <paramref name="apply"/> clause on the given <paramref name="elementType"/>, binding /// the text into a metadata-bound or dynamic properties to be applied using the provided model. /// </summary> /// <param name="apply">String representation of the apply expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the apply clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns> private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(apply, "apply"); // Get the syntactic representation of the apply expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var applyTokens = expressionParser.ParseApply(apply); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); ApplyBinder applyBinder = new ApplyBinder(binder.Bind, state); ApplyClause boundNode = applyBinder.BindApply(applyTokens); return boundNode; }
/// <summary> /// Parses an <paramref name="orderBy "/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="orderBy">String representation of the orderby expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the orderby clause refers to.</param> /// <param name="navigationSource">NavigationSource that the elements are from.</param> /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns> private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy"); // Get the syntactic representation of the orderby expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.OrderByLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); OrderByClause orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens); return orderByClause; }
/// <summary> /// Generate a select item <see cref="SelectItem"/> based on a <see cref="SelectTermToken"/>. /// for example: abc/efg($count=true;$filter=....;$top=1) /// </summary> /// <param name="tokenIn">the select term token to visit</param> /// <returns>the select item for this select term token.</returns> private SelectItem GenerateSelectItem(SelectTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); ExceptionUtils.CheckArgumentNotNull(tokenIn.PathToProperty, "pathToProperty"); VerifySelectedPath(tokenIn); SelectItem newSelectItem; if (ProcessWildcardTokenPath(tokenIn, out newSelectItem)) { return(newSelectItem); } IList <ODataPathSegment> selectedPath = ProcessSelectTokenPath(tokenIn.PathToProperty); Debug.Assert(selectedPath.Count > 0); // Navigation property should be the last segment in select path. if (VerifySelectedNavigationProperty(selectedPath, tokenIn)) { return(new PathSelectItem(new ODataSelectPath(selectedPath))); } // We should use the "NavigationSource" at this level for the next level binding. IEdmNavigationSource targetNavigationSource = this.NavigationSource; ODataPathSegment lastSegment = selectedPath.Last(); IEdmType targetElementType = lastSegment.TargetEdmType; IEdmCollectionType collection = targetElementType as IEdmCollectionType; if (collection != null) { targetElementType = collection.ElementType.Definition; } IEdmTypeReference elementTypeReference = targetElementType.ToTypeReference(); // $compute ComputeClause compute = BindCompute(tokenIn.ComputeOption, targetNavigationSource, elementTypeReference); HashSet <EndPathToken> generatedProperties = GetGeneratedProperties(compute, null); // $filter FilterClause filter = BindFilter(tokenIn.FilterOption, targetNavigationSource, elementTypeReference, generatedProperties); // $orderby OrderByClause orderBy = BindOrderby(tokenIn.OrderByOptions, targetNavigationSource, elementTypeReference, generatedProperties); // $search SearchClause search = BindSearch(tokenIn.SearchOption, targetNavigationSource, elementTypeReference); // $select List <ODataPathSegment> parsedPath = new List <ODataPathSegment>(this.parsedSegments); parsedPath.AddRange(selectedPath); SelectExpandClause selectExpand = BindSelectExpand(null, tokenIn.SelectOption, parsedPath, targetNavigationSource, elementTypeReference, generatedProperties); return(new PathSelectItem(new ODataSelectPath(selectedPath), targetNavigationSource, selectExpand, filter, orderBy, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, search, compute)); }
internal static IEdmCollectionType GetCollectionType(IEdmType itemType) { if (!itemType.IsODataPrimitiveTypeKind() && !itemType.IsODataComplexTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EdmLibraryExtensions_CollectionItemCanBeOnlyPrimitiveOrComplex); } return new EdmCollectionType(itemType.ToTypeReference()); }