private static EdmTypeKind ComputeTargetTypeKind(IEdmTypeReference expectedTypeReference, bool forEntityValue, string payloadTypeName, EdmTypeKind payloadTypeKind, ODataMessageReaderSettings messageReaderSettings, Func<EdmTypeKind> typeKindFromPayloadFunc) { EdmTypeKind kind; bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadTypeKind != EdmTypeKind.None); if (((expectedTypeReference != null) && !flag) && (!expectedTypeReference.IsODataPrimitiveTypeKind() || !messageReaderSettings.DisablePrimitiveTypeConversion)) { kind = expectedTypeReference.TypeKind(); } else if (payloadTypeKind != EdmTypeKind.None) { if (!forEntityValue) { ValidationUtils.ValidateValueTypeKind(payloadTypeKind, payloadTypeName); } kind = payloadTypeKind; } else { kind = typeKindFromPayloadFunc(); } if (ShouldValidatePayloadTypeKind(messageReaderSettings, expectedTypeReference, payloadTypeKind)) { ValidationUtils.ValidateTypeKind(kind, expectedTypeReference.TypeKind(), payloadTypeName); } return kind; }
internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext) { if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, propertyValue, propertyName, readContext.TimeZoneInfo); } else { if (!readContext.IsUntyped) { if (propertyKind == EdmTypeKind.Primitive) { propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue, GetPropertyType(resource, propertyName), readContext.TimeZoneInfo); } else if (propertyKind == EdmTypeKind.Enum) { propertyValue = EnumDeserializationHelpers.ConvertEnumValue(propertyValue, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, propertyValue); } }
internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext) { if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, propertyValue, propertyName); } else { if (!readContext.IsUntyped) { if (propertyKind == EdmTypeKind.Primitive) { propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue, GetPropertyType(resource, propertyName)); } else if (propertyKind == EdmTypeKind.Enum) { propertyValue = EnumDeserializationHelpers.ConvertEnumValue(propertyValue, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, propertyValue); } }
/// <summary> /// Parses a <paramref name="value"/> into an <see cref="IEdmExpression"/> value of the correct EDM type. /// </summary> /// <param name="edmType">The type of value.</param> /// <param name="value">The value to parse.</param> /// <returns> /// An IEdmExpression of type <paramref name="edmType" /> or null if the type is not supported/implemented. /// </returns> internal static IEdmExpression BuildEdmExpression(IEdmType edmType, string value) { EdmUtil.CheckArgumentNull(edmType, "edmType"); EdmUtil.CheckArgumentNull(value, "value"); EdmTypeKind termTypeKind = edmType.TypeKind; // Create expressions/constants for the corresponding types switch (termTypeKind) { case EdmTypeKind.Primitive: IEdmPrimitiveType primitiveTypeReference = (IEdmPrimitiveType)edmType; return(BuildEdmPrimitiveValueExp(primitiveTypeReference, value)); case EdmTypeKind.TypeDefinition: IEdmTypeDefinition typeDefinitionReference = (IEdmTypeDefinition)edmType; return(BuildEdmPrimitiveValueExp(typeDefinitionReference.UnderlyingType(), value)); case EdmTypeKind.Path: return(BuildEdmPathExp((IEdmPathType)edmType, value)); case EdmTypeKind.Enum: case EdmTypeKind.Complex: case EdmTypeKind.Entity: case EdmTypeKind.Collection: case EdmTypeKind.EntityReference: case EdmTypeKind.Untyped: default: throw new NotSupportedException(Strings.EdmVocabularyAnnotations_TermTypeNotSupported(edmType.FullTypeName())); } }
private static IEdmTypeReference GetEdmTypeReference(Dictionary <Type, IEdmType> availableTypes, IEdmTypeConfiguration configuration, bool nullable) { Contract.Assert(availableTypes != null); if (configuration == null) { return(null); } EdmTypeKind kind = configuration.Kind; if (kind == EdmTypeKind.Collection) { CollectionTypeConfiguration collectionType = (CollectionTypeConfiguration)configuration; EdmCollectionType edmCollectionType = new EdmCollectionType(GetEdmTypeReference(availableTypes, collectionType.ElementType, nullable)); return(new EdmCollectionTypeReference(edmCollectionType)); } else { Type configurationClrType = TypeHelper.GetUnderlyingTypeOrSelf(configuration.ClrType); if (!TypeHelper.IsEnum(configurationClrType)) { configurationClrType = configuration.ClrType; } IEdmType type; if (availableTypes.TryGetValue(configurationClrType, out type)) { if (kind == EdmTypeKind.Complex) { return(new EdmComplexTypeReference((IEdmComplexType)type, nullable)); } else if (kind == EdmTypeKind.Entity) { return(new EdmEntityTypeReference((IEdmEntityType)type, nullable)); } else if (kind == EdmTypeKind.Enum) { return(new EdmEnumTypeReference((IEdmEnumType)type, nullable)); } else { throw Error.InvalidOperation(SRResources.UnsupportedEdmTypeKind, kind.ToString()); } } else if (configuration.Kind == EdmTypeKind.Primitive) { PrimitiveTypeConfiguration primitiveTypeConfiguration = (PrimitiveTypeConfiguration)configuration; EdmPrimitiveTypeKind typeKind = EdmTypeBuilder.GetTypeKind(primitiveTypeConfiguration.ClrType); return(EdmCoreModel.Instance.GetPrimitive(typeKind, nullable)); } else { throw Error.InvalidOperation(SRResources.NoMatchingIEdmTypeFound, configuration.FullName); } } }
public static bool IsOrInheritsFrom(this IEdmType thisType, IEdmType otherType) { if (thisType == null || otherType == null) { return(false); } else { if (!thisType.IsEquivalentTo(otherType)) { EdmTypeKind typeKind = thisType.TypeKind; if (typeKind != otherType.TypeKind || typeKind != EdmTypeKind.Entity && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Row) { return(false); } else { return(thisType.IsOrInheritsFrom(otherType)); } } else { return(true); } } }
internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadType != null); if (!flag) { ValidateTypeSupported(expectedTypeReference, version); if (model.IsUserModel() && ((expectedTypeReference == null) || !messageReaderSettings.DisableStrictMetadataValidation)) { VerifyPayloadTypeDefined(payloadTypeName, payloadType); } } else { ValidateTypeSupported((payloadType == null) ? null : payloadType.ToTypeReference(true), version); } if ((payloadTypeKind != EdmTypeKind.None) && (!messageReaderSettings.DisableStrictMetadataValidation || (expectedTypeReference == null))) { ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName); } serializationTypeNameAnnotation = null; if (!model.IsUserModel()) { return null; } if ((expectedTypeReference == null) || flag) { return ResolveAndValidateTargetTypeWithNoExpectedType(expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } if (messageReaderSettings.DisableStrictMetadataValidation) { return ResolveAndValidateTargetTypeStrictValidationDisabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } return ResolveAndValidateTargetTypeStrictValidationEnabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); }
public static string ToTraceString(this IEdmType type) { EdmUtil.CheckArgumentNull <IEdmType>(type, "type"); EdmTypeKind typeKind = type.TypeKind; switch (typeKind) { case EdmTypeKind.Row: { return(((IEdmRowType)type).ToTraceString()); } case EdmTypeKind.Collection: { return(((IEdmCollectionType)type).ToTraceString()); } case EdmTypeKind.EntityReference: { return(((IEdmEntityReferenceType)type).ToTraceString()); } default: { IEdmSchemaType edmSchemaType = type as IEdmSchemaType; if (edmSchemaType == null) { break; } return(edmSchemaType.ToTraceString()); } } return("UnknownType"); }
/// <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()); }
private static EdmTypeKind ComputeTargetTypeKind(IEdmTypeReference expectedTypeReference, bool forEntityValue, string payloadTypeName, EdmTypeKind payloadTypeKind, ODataMessageReaderSettings messageReaderSettings, Func <EdmTypeKind> typeKindFromPayloadFunc) { EdmTypeKind kind; bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadTypeKind != EdmTypeKind.None); if (((expectedTypeReference != null) && !flag) && (!expectedTypeReference.IsODataPrimitiveTypeKind() || !messageReaderSettings.DisablePrimitiveTypeConversion)) { kind = expectedTypeReference.TypeKind(); } else if (payloadTypeKind != EdmTypeKind.None) { if (!forEntityValue) { ValidationUtils.ValidateValueTypeKind(payloadTypeKind, payloadTypeName); } kind = payloadTypeKind; } else { kind = typeKindFromPayloadFunc(); } if (ShouldValidatePayloadTypeKind(messageReaderSettings, expectedTypeReference, payloadTypeKind)) { ValidationUtils.ValidateTypeKind(kind, expectedTypeReference.TypeKind(), payloadTypeName); } return(kind); }
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)); }
internal static void ValidateValueTypeKind(EdmTypeKind typeKind, string typeName) { if (((typeKind != EdmTypeKind.Primitive) && (typeKind != EdmTypeKind.Complex)) && (typeKind != EdmTypeKind.Collection)) { throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncorrectValueTypeKind(typeName, typeKind.ToString())); } }
public static bool IsEquivalentTo(this IEdmType thisType, IEdmType otherType) { if (thisType != otherType) { if (thisType == null || otherType == null) { return(false); } else { if (thisType.TypeKind == otherType.TypeKind) { EdmTypeKind typeKind = thisType.TypeKind; switch (typeKind) { case EdmTypeKind.None: { return(otherType.TypeKind == EdmTypeKind.None); } case EdmTypeKind.Primitive: { return(thisType.IsEquivalentTo((IEdmPrimitiveType)otherType)); } case EdmTypeKind.Entity: case EdmTypeKind.Complex: case EdmTypeKind.Enum: { return(thisType.IsEquivalentTo((IEdmSchemaType)otherType)); } case EdmTypeKind.Row: { return(thisType.IsEquivalentTo((IEdmRowType)otherType)); } case EdmTypeKind.Collection: { return(thisType.IsEquivalentTo((IEdmCollectionType)otherType)); } case EdmTypeKind.EntityReference: { return(thisType.IsEquivalentTo((IEdmEntityReferenceType)otherType)); } } throw new InvalidOperationException(Strings.UnknownEnumVal_TypeKind(thisType.TypeKind)); } else { return(false); } } } else { return(true); } }
internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext, out EdmTypeKind typeKind) { if (oDataValue == null) { typeKind = EdmTypeKind.None; return(null); } ODataComplexValue complexValue = oDataValue as ODataComplexValue; if (complexValue != null) { typeKind = EdmTypeKind.Complex; return(ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext)); } ODataCollectionValue collection = oDataValue as ODataCollectionValue; if (collection != null) { typeKind = EdmTypeKind.Collection; Contract.Assert(propertyType != null, "Open collection properties are not supported."); return(ConvertCollectionValue(collection, propertyType, deserializerProvider, readContext)); } typeKind = EdmTypeKind.Primitive; return(oDataValue); }
/// <summary> /// Returns true if the compared type reference is semantically equivalent to this type reference. /// Schema types (<see cref="IEdmSchemaType"/>) are compared by their object refs. /// </summary> /// <param name="thisType">Type reference being compared.</param> /// <param name="otherType">Type referenced being compared to.</param> /// <returns>Equivalence of the two type references.</returns> public static bool IsEquivalentTo(this IEdmTypeReference thisType, IEdmTypeReference otherType) { if (thisType == otherType) { return(true); } if (thisType == null || otherType == null) { return(false); } thisType = thisType.AsActualTypeReference(); otherType = otherType.AsActualTypeReference(); EdmTypeKind typeKind = thisType.TypeKind(); if (typeKind != otherType.TypeKind()) { return(false); } if (typeKind == EdmTypeKind.Primitive) { return(((IEdmPrimitiveTypeReference)thisType).IsEquivalentTo((IEdmPrimitiveTypeReference)otherType)); } else { return(thisType.IsNullable == otherType.IsNullable && thisType.Definition.IsEquivalentTo(otherType.Definition)); } }
/// <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> /// Validates that the observed type kind is the expected type kind. /// </summary> /// <param name="actualTypeKind">The actual type kind to compare.</param> /// <param name="expectedTypeKind">The expected type kind to compare against.</param> /// <param name="expectStructuredType">This value indicates if the <paramref name="actualTypeKind"/> is expected to be complex or entity. /// True for complex or entity, false for non-structured type kind, null for indetermination.</param> /// <param name="typeName">The name of the type to use in the error.</param> internal static void ValidateTypeKind(EdmTypeKind actualTypeKind, EdmTypeKind expectedTypeKind, bool?expectStructuredType, string typeName) { if (expectStructuredType.HasValue && expectStructuredType.Value && (expectedTypeKind.IsStructured() || expectedTypeKind == EdmTypeKind.None) && actualTypeKind.IsStructured()) { return; } if (expectedTypeKind != actualTypeKind) { if (typeName == null) { throw new ODataException(Strings.ValidationUtils_IncorrectTypeKindNoTypeName(actualTypeKind.ToString(), expectedTypeKind.ToString())); } if (actualTypeKind == EdmTypeKind.TypeDefinition && expectedTypeKind == EdmTypeKind.Primitive || actualTypeKind == EdmTypeKind.Primitive && expectedTypeKind == EdmTypeKind.TypeDefinition || actualTypeKind == EdmTypeKind.Primitive && expectedTypeKind == EdmTypeKind.None) { return; } throw new ODataException(Strings.ValidationUtils_IncorrectTypeKind(typeName, expectedTypeKind.ToString(), actualTypeKind.ToString())); } }
internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext) { if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, propertyValue, propertyName); } else { var isUntypedProp = readContext.GetType().GetProperty("IsUntyped", BindingFlags.NonPublic | BindingFlags.Instance); bool isUntyped = (bool)isUntypedProp.GetValue(readContext, null); //if (!readContext.IsUntyped) if (!isUntyped) { if (propertyKind == EdmTypeKind.Primitive) { propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, propertyValue); } }
/// <summary> /// Read the value of the __metadata property and compute the payload kind based on the type name. /// </summary> /// <remarks>This method checks whether it can determine the type kind from the type name; if we /// find a primitive or collection type we set the result to empty since such payloads are not supported. /// Otherwise we'll treat the payload as an entry since top-level complex values are not supported either. /// Pre-Condition: Any The first node of the __metadata property value /// Post-Condition: Property or EndObject This method reads the entire value of the __metadata object and positions /// the reader on the next property or on the EndObject node if this is the last property. /// </remarks> private void ProcessMetadataPropertyValue() { // Clear all previously detected payload kinds since when we find a top-level __metadata // we base our decision solely on it. this.detectedPayloadKinds.Clear(); string typeName = this.ReadTypeNameFromMetadataPropertyValue(); // NOTE: we intentionally do not use the model passed to the message reader because we want to // keep the paylaod detection code independent of any model (at least for now). EdmTypeKind typeKind = EdmTypeKind.None; if (typeName != null) { MetadataUtils.ResolveTypeNameForRead( EdmCoreModel.Instance, /*expectedType*/ null, typeName, this.MessageReaderSettings.ReaderBehavior, this.Version, out typeKind); } // A valid top-level object with a __metadata property must not specify a primitive or collection type if (typeKind == EdmTypeKind.Primitive || typeKind == EdmTypeKind.Collection) { return; } Debug.Assert(typeKind == EdmTypeKind.None, "In the core model we should only be able to detect primitive and collection types."); // We don't support top-level complex value so the payload has to be an entry this.detectedPayloadKinds.Add(ODataPayloadKind.Entry); }
private static IEdmTypeReference ValidateMetadataType(IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue) { if (typeReferenceFromMetadata != null) { if (typeReferenceFromValue == null) { return(typeReferenceFromMetadata); } EdmTypeKind expectedTypeKind = typeReferenceFromMetadata.TypeKind(); ValidationUtils.ValidateTypeKind(typeReferenceFromValue.Definition, expectedTypeKind); if (typeReferenceFromValue.IsODataPrimitiveTypeKind()) { ValidationUtils.ValidateMetadataPrimitiveType(typeReferenceFromMetadata, typeReferenceFromValue); return(typeReferenceFromValue); } if (expectedTypeKind == EdmTypeKind.Entity) { ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)typeReferenceFromMetadata, (IEdmEntityTypeReference)typeReferenceFromValue); return(typeReferenceFromValue); } if (typeReferenceFromMetadata.ODataFullName() != typeReferenceFromValue.ODataFullName()) { throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncompatibleType(typeReferenceFromValue.ODataFullName(), typeReferenceFromMetadata.ODataFullName())); } } return(typeReferenceFromValue); }
private static IOpenApiAny CreateStructuredTypePropertiesExample(ODataContext context, IEdmStructuredType structuredType) { OpenApiObject example = new OpenApiObject(); IEdmEntityType entityType = structuredType as IEdmEntityType; // properties foreach (var property in structuredType.Properties()) { // IOpenApiAny item; IEdmTypeReference propertyType = property.Type; IOpenApiAny item = GetTypeNameForExample(context, propertyType); EdmTypeKind typeKind = propertyType.TypeKind(); if (typeKind == EdmTypeKind.Primitive && item is OpenApiString) { OpenApiString stringAny = item as OpenApiString; string value = stringAny.Value; if (entityType != null && entityType.Key().Any(k => k.Name == property.Name)) { value += " (identifier)"; } if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay()) { value += " (timestamp)"; } item = new OpenApiString(value); } example.Add(property.Name, item); } return(example); }
public EdmPrimitiveType(EdmPrimitiveTypeKind kind) { this.PrimitiveKind = kind; this.Namespace = "namespace"; this.Name = "name"; this.SchemaElementKind = EdmSchemaElementKind.None; this.TypeKind = EdmTypeKind.None; }
/// <summary> /// Checks whether a type refers to an OData Enumeration type /// </summary> /// <param name="type">The (non-null) <see cref="IEdmType"/> to check.</param> /// <returns>true if the <paramref name="type"/> is an OData enumeration type; otherwise false.</returns> internal static bool IsODataEnumTypeKind(this IEdmType type) { ExceptionUtils.CheckArgumentNotNull(type, "type"); EdmTypeKind typeKind = type.TypeKind; return(typeKind == EdmTypeKind.Enum); }
public CustomEnumType(string namespaceName, string name, IEdmPrimitiveType underlyingType) { this.typeKind = EdmTypeKind.Enum; this.name = name; this.namespaceName = namespaceName; this.isFlags = false; this.underlyingType = underlyingType; }
public CustomEnumType(string namespaceName, string name, EdmTypeKind typeKind) { this.typeKind = typeKind; this.name = name; this.namespaceName = namespaceName; this.isFlags = false; this.underlyingType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Int32); }
/// <summary> /// ODL callback for client type resolution /// </summary> /// <param name="expectedEdmType">The expected type for the given wire name</param> /// <param name="wireName">The name of the type from the payload</param> /// <returns>An IEdmType</returns> internal IEdmType ResolveWireTypeName(IEdmType expectedEdmType, string wireName) { // ODataLib should never pass an empty or null type name Debug.Assert(!String.IsNullOrEmpty(wireName), "!String.IsNullOrEmpty(wireName)"); // For V3 and above, ODataLib will never call the type resolver if there is a collection // type specified in the wire. However, in V1/V2, since there was no collection feature // supported, it will call us with a collection wire name, but its okay to return null // in that case, since there is no collection supported. If the user writes the type // resolver in such a way to handle collections themselves, even then it will fail later // in ODataLib stating collection types are not supported in V1/V2 versions. if (expectedEdmType != null) { // In V1/V2, we never used to call the type resolver for primitives types. // Instead, we just used to look at the expected property type and try to convert // the value from the payload to the expected property type. In other words, we // used to ignore the type name on the wire for primitive properties. if (expectedEdmType.TypeKind == EdmTypeKind.Primitive) { return(expectedEdmType); } } Type expectedType; if (expectedEdmType != null) { ClientTypeAnnotation expectedAnnotation = this.clientEdmModel.GetClientTypeAnnotation(expectedEdmType); Debug.Assert(expectedAnnotation != null, "expectedAnnotation != null"); expectedType = expectedAnnotation.ElementType; } else { expectedType = typeof(object); } // Breaking change: we decided to validate against the resolved type if the type are not assignable. Type resolvedType = this.ResolveTypeFromName(wireName, expectedType); ClientTypeAnnotation resolvedTypeAnnotation = this.clientEdmModel.GetClientTypeAnnotation(this.clientEdmModel.GetOrCreateEdmType(resolvedType)); Debug.Assert(resolvedTypeAnnotation != null, "result != null -- otherwise ClientType.Create returned null"); IEdmType clientEdmType = resolvedTypeAnnotation.EdmType; EdmTypeKind typeKind = clientEdmType.TypeKind; if (typeKind == EdmTypeKind.Entity || typeKind == EdmTypeKind.Complex) { // If the edm type name is not present in the dictionary, add it to the map string edmTypeName = clientEdmType.FullName(); if (!this.edmTypeNameMap.ContainsKey(edmTypeName)) { this.edmTypeNameMap.Add(edmTypeName, resolvedTypeAnnotation); } } return(clientEdmType); }
/// <summary> /// Resolves the name of a primitive, complex, entity or collection type to the respective type. Uses the semantics used be readers. /// Thus it can be a bit looser. /// </summary> /// <param name="model">The model to use.</param> /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param> /// <param name="typeName">The name of the type to resolve.</param> /// <param name="clientCustomTypeResolver">The function of client cuetom type resolver.</param> /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled /// even if the method returns null, for example for Collection types with item types which are not recognized.</param> /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>; /// or null if no such type could be found.</returns> internal static IEdmType ResolveTypeNameForRead( IEdmModel model, IEdmType expectedType, string typeName, Func <IEdmType, string, IEdmType> clientCustomTypeResolver, out EdmTypeKind typeKind) { return(ResolveTypeName(model, expectedType, typeName, clientCustomTypeResolver, out typeKind)); }
public void MeasuresVocabularyTypes(string termName, EdmTypeKind typeKind, string typeName) { var type = this.model.FindDeclaredType("Org.OData.Measures.V1." + termName); Assert.NotNull(type); Assert.Equal(typeKind, type.TypeKind); Assert.Equal(typeName, type.FullTypeName()); }
/// <summary> /// Validates a type kind for a value type. /// </summary> /// <param name="typeKind">The type kind.</param> /// <param name="typeName">The name of the type (used for error reporting only).</param> internal static void ValidateValueTypeKind(EdmTypeKind typeKind, string typeName) { Debug.Assert(typeName != null, "typeName != null"); if (typeKind != EdmTypeKind.Primitive && typeKind != EdmTypeKind.Enum && typeKind != EdmTypeKind.Complex && typeKind != EdmTypeKind.Collection) { throw new ODataException(Strings.ValidationUtils_IncorrectValueTypeKind(typeName, typeKind.ToString())); } }
/// <summary> /// Constructor. /// </summary> /// <param name="itemTypeNameFromCollection">The item type name extracted from the collection type name.</param> internal CollectionWithoutExpectedTypeValidator(string itemTypeNameFromCollection) { if (itemTypeNameFromCollection != null) { this.itemTypeName = GetItemTypeFullName(itemTypeNameFromCollection); this.itemTypeKind = ComputeExpectedTypeKind(this.itemTypeName, out this.primitiveItemType); this.itemTypeDerivedFromCollectionValue = true; } }
public void VisitTypeReference(IEdmTypeReference reference) { EdmTypeKind edmTypeKind = reference.TypeKind(); switch (edmTypeKind) { case EdmTypeKind.None: { this.ProcessTypeReference(reference); return; } case EdmTypeKind.Primitive: { this.VisitPrimitiveTypeReference(reference.AsPrimitive()); return; } case EdmTypeKind.Entity: { this.ProcessEntityTypeReference(reference.AsEntity()); return; } case EdmTypeKind.Complex: { this.ProcessComplexTypeReference(reference.AsComplex()); return; } case EdmTypeKind.Row: { this.ProcessRowTypeReference(reference.AsRow()); return; } case EdmTypeKind.Collection: { this.ProcessCollectionTypeReference(reference.AsCollection()); return; } case EdmTypeKind.EntityReference: { this.ProcessEntityReferenceTypeReference(reference.AsEntityReference()); return; } case EdmTypeKind.Enum: { this.ProcessEnumTypeReference(reference.AsEnum()); return; } } throw new InvalidOperationException(Strings.UnknownEnumVal_TypeKind(reference.TypeKind().ToString())); }
internal static IEdmType ResolveTypeName( IEdmModel model, IEdmType expectedType, string typeName, Func <IEdmType, string, IEdmType> customTypeResolver, ODataVersion version, out EdmTypeKind typeKind) { Debug.Assert(model != null, "model != null"); Debug.Assert(typeName != null, "typeName != null"); IEdmType resolvedType = null; // Collection types should only be recognized in V3 and higher. string itemTypeName = EdmLibraryExtensions.GetCollectionItemTypeName(typeName); if (itemTypeName == null) { // Note: we require the type resolver or the model to also resolve // primitive types. if (customTypeResolver != null && model.IsUserModel()) { resolvedType = customTypeResolver(expectedType, typeName); if (resolvedType == null) { // If a type resolver is specified it must never return null. throw new ODataException(Strings.MetadataUtils_ResolveTypeName(typeName)); } } else { resolvedType = model.FindType(typeName); } typeKind = resolvedType == null ? EdmTypeKind.None : resolvedType.TypeKind; } else { // Collection typeKind = EdmTypeKind.Collection; EdmTypeKind itemTypeKind; IEdmType expectedItemType = null; if (customTypeResolver != null && expectedType != null && expectedType.TypeKind == EdmTypeKind.Collection) { expectedItemType = ((IEdmCollectionType)expectedType).ElementType.Definition; } IEdmType itemType = ResolveTypeName(model, expectedItemType, itemTypeName, customTypeResolver, version, out itemTypeKind); if (itemType != null) { resolvedType = EdmLibraryExtensions.GetCollectionType(itemType); } } return(resolvedType); }
/// <summary> /// Constructor. /// </summary> /// <param name="itemTypeNameFromCollection">The item type name extracted from the collection type name.</param> internal CollectionWithoutExpectedTypeValidator(string itemTypeNameFromCollection) { DebugUtils.CheckNoExternalCallers(); if (itemTypeNameFromCollection != null) { this.itemTypeName = itemTypeNameFromCollection; this.itemTypeKind = ComputeExpectedTypeKind(this.itemTypeName, out this.primitiveItemType); this.itemTypeDerivedFromCollectionValue = true; } }
/// <summary> /// Returns true if this type kind represents a structured type. /// </summary> /// <param name="typeKind">Reference to the calling object.</param> /// <returns>This kind refers to a structured type.</returns> public static bool IsStructured(this EdmTypeKind typeKind) { switch (typeKind) { case EdmTypeKind.Entity: case EdmTypeKind.Complex: return(true); } return(false); }
/// <summary> /// Validates that the observed type kind is the expected type kind. /// </summary> /// <param name="actualTypeKind">The actual type kind.</param> /// <param name="expectedTypeKind">The expected type kind.</param> /// <param name="expectStructuredType">This value indicates if the <paramref name="actualTypeKind"/> is expected to be complex or entity. /// True for complex or entity, false for non-structured type kind, null for indetermination.</param> /// <param name="edmType">The edm type to use in the error.</param> /// <remarks>If expectedStructuredType is true, then expectedTypeKind could be </remarks> public virtual void ValidateTypeKind(EdmTypeKind actualTypeKind, EdmTypeKind expectedTypeKind, bool?expectStructuredType, IEdmType edmType) { if (settings.ThrowIfTypeConflictsWithMetadata) { ValidationUtils.ValidateTypeKind( actualTypeKind, expectedTypeKind, expectStructuredType, edmType == null ? null : edmType.FullTypeName()); } }
internal static void SetDynamicProperty(object resource, IEdmStructuredTypeReference resourceType, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmTypeReference propertyType, ODataDeserializerContext readContext, AssembliesResolver assembliesResolver) { if (propertyKind == EdmTypeKind.Collection && propertyValue.GetType() != typeof(EdmComplexObjectCollection) && propertyValue.GetType() != typeof(EdmEnumObjectCollection)) { SetDynamicCollectionProperty(resource, propertyName, propertyValue, propertyType.AsCollection(), resourceType.StructuredDefinition(), readContext, assembliesResolver); } else { SetDynamicProperty(resource, propertyName, propertyValue, resourceType.StructuredDefinition(), readContext); } }
internal void ValidateCollectionItem(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind) { if ((collectionItemTypeKind != EdmTypeKind.Primitive) && (collectionItemTypeKind != EdmTypeKind.Complex)) { throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_InvalidItemTypeKind(collectionItemTypeKind)); } if (this.itemTypeDerivedFromCollectionValue) { collectionItemTypeName = collectionItemTypeName ?? this.itemTypeName; this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind); } else { if (this.itemTypeKind == EdmTypeKind.None) { this.itemTypeKind = (collectionItemTypeName == null) ? collectionItemTypeKind : ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType); if (collectionItemTypeName == null) { this.itemTypeKind = collectionItemTypeKind; if (this.itemTypeKind == EdmTypeKind.Primitive) { this.itemTypeName = "Edm.String"; this.primitiveItemType = EdmCoreModel.Instance.GetString(false).PrimitiveDefinition(); } else { this.itemTypeName = null; this.primitiveItemType = null; } } else { this.itemTypeKind = ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType); this.itemTypeName = collectionItemTypeName; } } if ((collectionItemTypeName == null) && (collectionItemTypeKind == EdmTypeKind.Primitive)) { collectionItemTypeName = "Edm.String"; } this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind); } }
internal static IEdmTypeReference ResolveTypeNameForWriting(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ref string typeName, EdmTypeKind typeKindFromValue, bool isOpenPropertyType) { IEdmType type = ValidateValueTypeName(model, typeName, typeKindFromValue, isOpenPropertyType); IEdmTypeReference typeReferenceFromValue = type.ToTypeReference(); if (typeReferenceFromMetadata != null) { ValidationUtils.ValidateTypeKind(typeKindFromValue, typeReferenceFromMetadata.TypeKind(), (type == null) ? null : type.ODataFullName()); } typeReferenceFromValue = ValidateMetadataType(typeReferenceFromMetadata, typeReferenceFromValue); if ((typeKindFromValue == EdmTypeKind.Collection) && (typeReferenceFromValue != null)) { typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue); } if ((typeName == null) && (typeReferenceFromValue != null)) { typeName = typeReferenceFromValue.ODataFullName(); } return typeReferenceFromValue; }
/// <summary> /// Validates a type name to ensure that it's not an empty string. /// </summary> /// <param name="model">The model to use.</param> /// <param name="typeName">The type name to validate.</param> /// <param name="typeKind">The expected type kind for the given type name.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <returns>The type with the given name and kind if the model is a user model, otherwise null.</returns> internal static IEdmType ValidateValueTypeName(IEdmModel model, string typeName, EdmTypeKind typeKind, bool isOpenPropertyType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(model != null, "model != null"); Debug.Assert(typeKind != EdmTypeKind.Entity, "This method is only for value types."); if (typeName == null) { // if we have metadata the type name of an entry or a complex value of an open property must not be null if (model.IsUserModel() && isOpenPropertyType) { throw new ODataException(Strings.WriterValidationUtils_MissingTypeNameWithMetadata); } return null; } return ValidationUtils.ValidateValueTypeName(model, typeName, typeKind); }
internal static void SetDynamicProperty(object resource, IEdmStructuredTypeReference resourceType, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmTypeReference propertyType, ODataDeserializerContext readContext) { if (propertyKind == EdmTypeKind.Collection) { SetDynamicCollectionProperty(resource, propertyName, propertyValue, propertyType.AsCollection(), resourceType.StructuredDefinition(), readContext); } else { if (propertyKind == EdmTypeKind.Enum) { propertyValue = ConvertDynamicEnumValue(propertyValue, readContext); } SetDynamicProperty(resource, propertyName, propertyValue, resourceType.StructuredDefinition(), readContext); } }
private void ValidateCollectionItemTypeNameAndKind(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind) { if (this.itemTypeKind != collectionItemTypeKind) { throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeKind(collectionItemTypeKind, this.itemTypeKind)); } if (this.itemTypeKind == EdmTypeKind.Primitive) { if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) == 0) { return; } if (this.primitiveItemType.IsSpatial()) { EdmPrimitiveTypeKind primitiveTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(collectionItemTypeName); IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(primitiveTypeKind); if (this.itemTypeDerivedFromCollectionValue) { if (this.primitiveItemType.IsAssignableFrom(primitiveType)) { return; } } else { IEdmPrimitiveType commonBaseType = this.primitiveItemType.GetCommonBaseType(primitiveType); if (commonBaseType != null) { this.primitiveItemType = commonBaseType; this.itemTypeName = commonBaseType.ODataFullName(); return; } } } throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName)); } if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) != 0) { throw new ODataException(Microsoft.Data.OData.Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName)); } }
private static IEdmType ResolveTypeName(IEdmModel model, IEdmType expectedType, string typeName, Func<IEdmType, string, IEdmType> customTypeResolver, ODataVersion version, out EdmTypeKind typeKind) { IEdmType collectionType = null; EdmTypeKind kind; string str = (version >= ODataVersion.V3) ? EdmLibraryExtensions.GetCollectionItemTypeName(typeName) : null; if (str == null) { if ((customTypeResolver != null) && model.IsUserModel()) { collectionType = customTypeResolver(expectedType, typeName); if (collectionType == null) { throw new ODataException(Microsoft.Data.OData.Strings.MetadataUtils_ResolveTypeName(typeName)); } } else { collectionType = model.FindType(typeName); } if (((version < ODataVersion.V3) && (collectionType != null)) && collectionType.IsSpatial()) { collectionType = null; } typeKind = (collectionType == null) ? EdmTypeKind.None : collectionType.TypeKind; return collectionType; } typeKind = EdmTypeKind.Collection; IEdmType definition = null; if (((customTypeResolver != null) && (expectedType != null)) && (expectedType.TypeKind == EdmTypeKind.Collection)) { definition = ((IEdmCollectionType) expectedType).ElementType.Definition; } IEdmType itemType = ResolveTypeName(model, definition, str, customTypeResolver, version, out kind); if (itemType != null) { collectionType = EdmLibraryExtensions.GetCollectionType(itemType); } return collectionType; }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed when the strict validation is disabled. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType) { // Lax validation logic switch (expectedTypeKind) { case EdmTypeKind.Complex: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { // Verify if it's a derived complex type, in all other cases simply use the expected type. VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ false); if (EdmLibraryExtensions.IsAssignableFrom(expectedTypeReference.AsComplex().ComplexDefinition(), (IEdmComplexType)payloadType)) { return payloadType.ToTypeReference(/*nullable*/ true); } } break; case EdmTypeKind.Entity: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { // If the type is assignable (equal or derived) we will use the payload type, since we want to allow derived entities if (EdmLibraryExtensions.IsAssignableFrom(expectedTypeReference.AsEntity().EntityDefinition(), (IEdmEntityType)payloadType)) { IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); return payloadTypeReference; } } break; case EdmTypeKind.Collection: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; case EdmTypeKind.Enum: // enum: no validation break; case EdmTypeKind.TypeDefinition: // type definition: no validation break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal. return expectedTypeReference; }
internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext, out EdmTypeKind typeKind) { if (oDataValue == null) { typeKind = EdmTypeKind.None; return null; } ODataComplexValue complexValue = oDataValue as ODataComplexValue; if (complexValue != null) { typeKind = EdmTypeKind.Complex; return ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext); } ODataEnumValue enumValue = oDataValue as ODataEnumValue; if (enumValue != null) { typeKind = EdmTypeKind.Enum; return ConvertEnumValue(enumValue, ref propertyType, deserializerProvider, readContext); } ODataCollectionValue collection = oDataValue as ODataCollectionValue; if (collection != null) { typeKind = EdmTypeKind.Collection; return ConvertCollectionValue(collection, ref propertyType, deserializerProvider, readContext); } typeKind = EdmTypeKind.Primitive; return oDataValue; }
/// <summary> /// Validates a collection item that was read to make sure it is valid (i.e., has the correct /// type name and type kind) with respect to the other items in the collection. /// </summary> /// <param name="collectionItemTypeName">The type name of the item from the payload.</param> /// <param name="collectionItemTypeKind">The type kind of the item from the payload.</param> internal void ValidateCollectionItem(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind) { // Only primitive and complex values are allowed in collections if (collectionItemTypeKind != EdmTypeKind.Primitive && collectionItemTypeKind != EdmTypeKind.Enum && collectionItemTypeKind != EdmTypeKind.Complex) { throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_InvalidItemTypeKind(collectionItemTypeKind)); } if (this.itemTypeDerivedFromCollectionValue) { Debug.Assert(this.itemTypeName != null, "this.itemType != null"); // If the collection has a type name assign missing item type names from it. collectionItemTypeName = collectionItemTypeName ?? this.itemTypeName; // If we have a type name from the collection, make sure the type names of all items match this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind); } else { // If we don't have a type name from the collection, store the type name and type kind of the first non-null item. if (this.itemTypeKind == EdmTypeKind.None) { // Compute the kind from the specified type name if available. this.itemTypeKind = collectionItemTypeName == null ? collectionItemTypeKind : ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType); // If no payload type name is specified either default to Edm.String (for primitive type kinds) or leave the type name // null (for complex items without type name) if (collectionItemTypeName == null) { this.itemTypeKind = collectionItemTypeKind; if (this.itemTypeKind == EdmTypeKind.Primitive) { this.itemTypeName = Metadata.EdmConstants.EdmStringTypeName; this.primitiveItemType = EdmCoreModel.Instance.GetString(/*isNullable*/ false).PrimitiveDefinition(); } else { this.itemTypeName = null; this.primitiveItemType = null; } } else { this.itemTypeKind = ComputeExpectedTypeKind(collectionItemTypeName, out this.primitiveItemType); this.itemTypeName = collectionItemTypeName; } } if (collectionItemTypeName == null && collectionItemTypeKind == EdmTypeKind.Primitive) { // Default to Edm.String if no payload type is specified and the type kind is 'Primitive' collectionItemTypeName = Metadata.EdmConstants.EdmStringTypeName; } // Validate the expected and actual type names and type kinds. // Note that we compute the expected type kind from the expected type name and thus the payload // type kind (passed to this method) might be different from the computed expected type kind. this.ValidateCollectionItemTypeNameAndKind(collectionItemTypeName, collectionItemTypeKind); } }
/// <summary> /// Resolves the payload type if there's no expected type. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType( EdmTypeKind expectedTypeKind, IEdmType payloadType) { // No expected type (for example an open property, but other scenarios are possible) // We need some type to go on. We do have a model, so we must perform metadata validation and for that we need a type. if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Strings.ReaderValidationUtils_EntryWithoutType); } return null; // supports undeclared property } // Payload types are always nullable. IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); // Use the payload type (since we don't have any other). return payloadTypeReference; }
/// <summary> /// Validate that the expected and actual type names and type kinds are compatible. /// </summary> /// <param name="collectionItemTypeName">The actual type name.</param> /// <param name="collectionItemTypeKind">The actual type kind.</param> private void ValidateCollectionItemTypeNameAndKind(string collectionItemTypeName, EdmTypeKind collectionItemTypeKind) { // Compare the item type kinds. if (this.itemTypeKind != collectionItemTypeKind) { throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeKind(collectionItemTypeKind, this.itemTypeKind)); } if (this.itemTypeKind == EdmTypeKind.Primitive) { Debug.Assert(this.primitiveItemType != null, "this.primitiveItemType != null"); Debug.Assert(collectionItemTypeName != null, "collectionItemTypeName != null"); // NOTE: we do support type inheritance for spatial primitive types; otherwise the type names have to match. if (!string.IsNullOrEmpty(this.itemTypeName) && this.itemTypeName.Equals(collectionItemTypeName, System.StringComparison.OrdinalIgnoreCase)) { return; } if (this.primitiveItemType.IsSpatial()) { EdmPrimitiveTypeKind collectionItemPrimitiveKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(collectionItemTypeName); IEdmPrimitiveType collectionItemPrimitiveType = EdmCoreModel.Instance.GetPrimitiveType(collectionItemPrimitiveKind); if (this.itemTypeDerivedFromCollectionValue) { // If the collection defines an item type, the collection item type has to be assignable to it. if (this.primitiveItemType.IsAssignableFrom(collectionItemPrimitiveType)) { return; } } else { // If the collection does not define an item type, the collection items must have a common base type. IEdmPrimitiveType commonBaseType = EdmLibraryExtensions.GetCommonBaseType(this.primitiveItemType, collectionItemPrimitiveType); if (commonBaseType != null) { this.primitiveItemType = commonBaseType; this.itemTypeName = commonBaseType.FullTypeName(); return; } } } throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName)); } else { // Since we do not support type inheritance for complex types, comparison of the type names is sufficient if (string.CompareOrdinal(this.itemTypeName, collectionItemTypeName) != 0) { throw new ODataException(Strings.CollectionWithoutExpectedTypeValidator_IncompatibleItemTypeName(collectionItemTypeName, this.itemTypeName)); } } }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeKind">The payload type kind, this may be the one from the type itself, or one detected without resolving the type.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="model">The model to use.</param> /// <param name="messageReaderSettings">The message reader settings to use.</param> /// <returns> /// The target type reference to use for parsing the value. /// If there is no user specified model, this will return null. /// If there is a user specified model, this method never returns null. /// </returns> /// <remarks> /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead. /// </remarks> internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings) { Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null"); Debug.Assert( expectedTypeKind == EdmTypeKind.Enum || expectedTypeKind == EdmTypeKind.Complex || expectedTypeKind == EdmTypeKind.Entity || expectedTypeKind == EdmTypeKind.Collection || expectedTypeKind == EdmTypeKind.TypeDefinition, "The expected type kind must be one of Enum, Complex, Entity, Collection or TypeDefinition."); Debug.Assert( payloadTypeKind == EdmTypeKind.Complex || payloadTypeKind == EdmTypeKind.Entity || payloadTypeKind == EdmTypeKind.Collection || payloadTypeKind == EdmTypeKind.None || payloadTypeKind == EdmTypeKind.Primitive || payloadTypeKind == EdmTypeKind.Enum || payloadTypeKind == EdmTypeKind.TypeDefinition, "The payload type kind must be one of None, Primitive, Enum, Complex, Entity, Collection or TypeDefinition."); Debug.Assert( expectedTypeReference == null || expectedTypeReference.TypeKind() == expectedTypeKind, "The expected type kind must match the expected type reference if that is available."); Debug.Assert( payloadType == null || payloadType.TypeKind == payloadTypeKind, "The payload type kind must match the payload type if that is available."); Debug.Assert(payloadType == null || payloadTypeName != null, "If we have a payload type, we must have its name as well."); bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadType != null; if (!useExpectedTypeOnlyForTypeResolution) { ValidateTypeSupported(expectedTypeReference); // We should validate that the payload type resolved before anything else to produce reasonable error messages // Otherwise we might report errors which are somewhat confusing (like "Type '' is Complex but Collection was expected."). if (model.IsUserModel() && (expectedTypeReference == null || !messageReaderSettings.DisableStrictMetadataValidation)) { // When using a type resolver (i.e., useExpectedTypeOnlyForTypeResolution == true) then we don't have to // call this method because the contract with the type resolver is to always resolve the type name and thus // we will always get a defined type. VerifyPayloadTypeDefined(payloadTypeName, payloadType); } } else { // Payload types are always nullable. ValidateTypeSupported(payloadType == null ? null : payloadType.ToTypeReference(/*nullable*/ true)); } // In lax mode don't cross check kinds of types (we would just use the expected type) unless we expect // an open property of a specific kind (e.g. top level complex property for PUT requests) if (payloadTypeKind != EdmTypeKind.None && (!messageReaderSettings.DisableStrictMetadataValidation || expectedTypeReference == null)) { // Make sure that the type kinds match. ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName); } if (!model.IsUserModel()) { // If there's no model, it means we should not have the expected type either, and that there's no type to use, // no metadata validation to perform. Debug.Assert(expectedTypeReference == null, "If we don't have a model, we must not have expected type either."); return null; } if (expectedTypeReference == null || useExpectedTypeOnlyForTypeResolution) { Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here."); return ResolveAndValidateTargetTypeWithNoExpectedType( expectedTypeKind, payloadType); } if (messageReaderSettings.DisableStrictMetadataValidation) { return ResolveAndValidateTargetTypeStrictValidationDisabled( expectedTypeKind, expectedTypeReference, payloadType); } Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here."); return ResolveAndValidateTargetTypeStrictValidationEnabled( expectedTypeKind, expectedTypeReference, payloadType); }
/// <summary> /// Resolves and validates the payload type against the expected type and returns the target type. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="defaultPrimitivePayloadType">The default payload type if none is specified in the payload; /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="model">The model to use.</param> /// <param name="messageReaderSettings">The message reader settings to use.</param> /// <param name="typeKindFromPayloadFunc">A func to compute the type kind from the payload shape if it could not be determined from the expected type or the payload type.</param> /// <param name="targetTypeKind">The target type kind to be used to read the payload.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns> /// The target type reference to use for parsing the value. /// If there is no user specified model, this will return null. /// If there is a user specified model, this method never returns null. /// </returns> /// <remarks> /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead. /// </remarks> internal static IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind expectedTypeKind, IEdmType defaultPrimitivePayloadType, IEdmTypeReference expectedTypeReference, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, Func<EdmTypeKind> typeKindFromPayloadFunc, out EdmTypeKind targetTypeKind, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { Debug.Assert(typeKindFromPayloadFunc != null, "typeKindFromPayloadFunc != null"); serializationTypeNameAnnotation = null; // What is the right behavior if both expected and actual types are specified for complex value? // We decided that they have to match exactly. // Resolve the type name and get the payload type kind; that is the type kind of the payload // type if available or the expected type kind if no payload type could be resolved. Since // we always detect primitive and collection types the expected type for unrecognized payload // types is EdmTypeKind.Complex. EdmTypeKind payloadTypeKind; IEdmType payloadType = ResolvePayloadTypeName( model, expectedTypeReference, payloadTypeName, EdmTypeKind.Complex, messageReaderSettings.ReaderBehavior, out payloadTypeKind); // Compute the target type kind based on the expected type, the payload type kind // and a function to detect the target type kind from the shape of the payload. targetTypeKind = ComputeTargetTypeKind( expectedTypeReference, /*forEntityValue*/ expectedTypeKind == EdmTypeKind.Entity, payloadTypeName, payloadTypeKind, messageReaderSettings, typeKindFromPayloadFunc); // Resolve potential conflicts between payload and expected types and apply all the various behavior changing flags from settings IEdmTypeReference targetTypeReference; if (targetTypeKind == EdmTypeKind.Primitive) { targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType( expectedTypeReference, payloadTypeKind, payloadType, payloadTypeName, defaultPrimitivePayloadType, model, messageReaderSettings); } else { targetTypeReference = ReaderValidationUtils.ResolveAndValidateNonPrimitiveTargetType( targetTypeKind, expectedTypeReference, payloadTypeKind, payloadType, payloadTypeName, model, messageReaderSettings); if (targetTypeReference != null) { serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); } } if (expectedTypeKind != EdmTypeKind.None && targetTypeReference != null) { ValidationUtils.ValidateTypeKind(targetTypeKind, expectedTypeKind, payloadTypeName); } return targetTypeReference; }
/// <summary> /// Resolves the primitive payload type versus the expected type and validates that such combination is allowed. /// </summary> /// <param name="expectedTypeReference">The expected type reference, if any.</param> /// <param name="payloadTypeKind">The kind of the payload type, or None if the detection was not possible.</param> /// <param name="payloadType">The resolved payload type, or null if no payload type was specified.</param> /// <param name="payloadTypeName">The name of the payload type, or null if no payload type was specified.</param> /// <param name="defaultPayloadType">The default payload type if none is specified in the payload; /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param> /// <param name="model">The model to use.</param> /// <param name="messageReaderSettings">The message reader settings to use.</param> /// <returns>The target type reference to use for parsing the value. This method never returns null.</returns> internal static IEdmTypeReference ResolveAndValidatePrimitiveTargetType( IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmType defaultPayloadType, IEdmModel model, ODataMessageReaderSettings messageReaderSettings) { Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null"); Debug.Assert( payloadTypeKind == EdmTypeKind.Primitive || payloadTypeKind == EdmTypeKind.Complex || payloadTypeKind == EdmTypeKind.Entity || payloadTypeKind == EdmTypeKind.Collection || payloadTypeKind == EdmTypeKind.None || payloadTypeKind == EdmTypeKind.TypeDefinition, "The payload type kind must be one of None, Primitive, Complex, Entity, Collection or TypeDefinition."); Debug.Assert( expectedTypeReference == null || expectedTypeReference.TypeKind() == EdmTypeKind.Primitive, "This method only works for primitive expected type."); Debug.Assert( payloadType == null || payloadType.TypeKind == payloadTypeKind, "The payload type kind must match the payload type if that is available."); Debug.Assert(payloadType == null || payloadTypeName != null, "If we have a payload type, we must have its name as well."); bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadType != null; if (expectedTypeReference != null && !useExpectedTypeOnlyForTypeResolution) { ValidateTypeSupported(expectedTypeReference); } // Validate type kinds except for open properties or when in lax mode, but only if primitive type conversion is enabled. // If primitive type conversion is disabled, the type kind must match, no matter what validation mode is used. // The rules for primitive types are: // - In the strict mode the payload value must be convertible to the expected type. So the payload type must be a primitive type. // - In the lax mode the payload type is ignored, so its type kind is not verified in any way // - If the DisablePrimitiveTypeConversion == true, the lax/strict mode doesn't matter and we will read the payload value on its own. // In this case we require the payload value to always be a primitive type (so type kinds must match), but it may not be convertible // to the expected type, it will still be reported to the caller. if (payloadTypeKind != EdmTypeKind.None && (messageReaderSettings.DisablePrimitiveTypeConversion || !messageReaderSettings.DisableStrictMetadataValidation)) { // Make sure that the type kinds match. ValidationUtils.ValidateTypeKind(payloadTypeKind, EdmTypeKind.Primitive, payloadTypeName); } if (!model.IsUserModel()) { // If there's no model, it means we should not have the expected type either, and that there's no type to use, // no metadata validation to perform. Debug.Assert(expectedTypeReference == null, "If we don't have a model, we must not have expected type either."); return MetadataUtils.GetNullablePayloadTypeReference(payloadType ?? defaultPayloadType); } // If the primitive type conversion is off, use the payload type always. // If there's no expected type or the expected type is ignored, use the payload type as well. if (expectedTypeReference == null || useExpectedTypeOnlyForTypeResolution || messageReaderSettings.DisablePrimitiveTypeConversion) { // If there's no payload type, use the default payload type. // Note that in collections the items without type should inherit the type name from the collection, in that case the expectedTypeReference // is never null (assuming we do have a model), so we won't get here. return MetadataUtils.GetNullablePayloadTypeReference(payloadType ?? defaultPayloadType); } // The server ignores the payload type when expected type is specified // The server is going to use lax mode everywhere so this is not an issue. if (messageReaderSettings.DisableStrictMetadataValidation) { // Lax validation logic // Always use the expected type, the payload type is ignored. return expectedTypeReference; } // Strict validation logic // We assume the expected type in the case where no payload type is specified // for a primitive value (in strict mode); if no expected type is available we assume Edm.String. if (payloadType != null) { // The payload type must be convertible to the expected type. // Note that we compare the type definitions, since we want to ignore nullability (the payload type doesn't specify nullability). if (!MetadataUtilsCommon.CanConvertPrimitiveTypeTo( null /* sourceNodeOrNull */, (IEdmPrimitiveType)payloadType.AsActualType(), (IEdmPrimitiveType)(expectedTypeReference.Definition))) { throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadTypeName, expectedTypeReference.ODataFullName())); } } // Read using the expected type. // If there was a payload type we verified that it's convertible and thus we can safely read // the content of the value as the expected type. return expectedTypeReference; }
/// <summary> /// Resolved the payload type name to the type. /// </summary> /// <param name="model">The model to use for the resolution.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeName">The payload type name to resolve.</param> /// <param name="expectedTypeKind">The default payload type kind, this is used when the resolution is not possible, /// but the type name is not empty. (Should be either Complex or Entity).</param> /// <param name="readerBehavior">Reader behavior to use for compatibility.</param> /// <param name="payloadTypeKind">This is set to the detected payload type kind, or None if the type was not specified.</param> /// <returns>The resolved type. This may be null if either no user-specified model is specified, or the type name is not recognized by the model.</returns> /// <remarks>The method detects the payload kind even if the model does not recognize the type. It figures out primitive and collection types always, /// and uses the <paramref name="expectedTypeKind"/> for the rest.</remarks> internal static IEdmType ResolvePayloadTypeName( IEdmModel model, IEdmTypeReference expectedTypeReference, string payloadTypeName, EdmTypeKind expectedTypeKind, ODataReaderBehavior readerBehavior, out EdmTypeKind payloadTypeKind) { if (payloadTypeName == null) { payloadTypeKind = EdmTypeKind.None; return null; } // Empty type names are allowed. if (payloadTypeName.Length == 0) { payloadTypeKind = expectedTypeKind; return null; } IEdmType payloadType = MetadataUtils.ResolveTypeNameForRead( model, expectedTypeReference == null ? null : expectedTypeReference.Definition, payloadTypeName, readerBehavior, out payloadTypeKind); if (payloadTypeKind == EdmTypeKind.None) { payloadTypeKind = expectedTypeKind; } return payloadType; }
/// <summary> /// Resolves the name of a primitive, complex, entity or collection type to the respective type. Uses the semantics used be readers. /// Thus it can be a bit looser. /// </summary> /// <param name="model">The model to use or null if no model is available.</param> /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param> /// <param name="typeName">The name of the type to resolve.</param> /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param> /// <param name="version">The version of the payload being read.</param> /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled /// even if the method returns null, for example for Collection types with item types which are not recognized.</param> /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>; /// or null if no such type could be found.</returns> internal static IEdmType ResolveTypeNameForRead( IEdmModel model, IEdmType expectedType, string typeName, ODataReaderBehavior readerBehavior, ODataVersion version, out EdmTypeKind typeKind) { DebugUtils.CheckNoExternalCallers(); Func<IEdmType, string, IEdmType> customTypeResolver = readerBehavior == null ? null : readerBehavior.TypeResolver; Debug.Assert( customTypeResolver == null || readerBehavior.ApiBehaviorKind == ODataBehaviorKind.WcfDataServicesClient, "Custom type resolver can only be specified in WCF DS Client behavior."); return ResolveTypeName(model, expectedType, typeName, customTypeResolver, version, out typeKind); }
internal static IEdmType ResolveTypeNameForRead(IEdmModel model, IEdmType expectedType, string typeName, ODataReaderBehavior readerBehavior, ODataVersion version, out EdmTypeKind typeKind) { Func<IEdmType, string, IEdmType> customTypeResolver = (readerBehavior == null) ? null : readerBehavior.TypeResolver; return ResolveTypeName(model, expectedType, typeName, customTypeResolver, version, out typeKind); }
internal static object ConvertValue(object oDataValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext, out EdmTypeKind typeKind) { if (oDataValue == null) { typeKind = EdmTypeKind.None; return null; } ODataComplexValue complexValue = oDataValue as ODataComplexValue; if (complexValue != null) { typeKind = EdmTypeKind.Complex; return ConvertComplexValue(complexValue, ref propertyType, deserializerProvider, readContext); } ODataCollectionValue collection = oDataValue as ODataCollectionValue; if (collection != null) { typeKind = EdmTypeKind.Collection; Contract.Assert(propertyType != null, "Open collection properties are not supported."); return ConvertCollectionValue(collection, propertyType, deserializerProvider, readContext); } typeKind = EdmTypeKind.Primitive; return oDataValue; }
/// <summary> /// Determines if the expect value type and the current settings mandate us to validate type kinds of payload values. /// </summary> /// <param name="messageReaderSettings">The message reader settings.</param> /// <param name="expectedValueTypeReference">The expected type reference for the value infered from the model.</param> /// <param name="payloadTypeKind">The type kind of the payload value.</param> /// <returns>true if the payload value kind must be verified, false otherwise.</returns> /// <remarks>This method deals with the strict versus lax behavior, as well as with the behavior when primitive type conversion is disabled.</remarks> private static bool ShouldValidatePayloadTypeKind(ODataMessageReaderSettings messageReaderSettings, IEdmTypeReference expectedValueTypeReference, EdmTypeKind payloadTypeKind) { // If we have a type resolver, we always use the type returned by the resolver // and use the expected type only for the resolution. bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadTypeKind != EdmTypeKind.None; // Type kind validation must happen when // - In strict mode // - Target type is primitive and primitive type conversion is disabled // In lax mode we don't want to validate type kinds, but the DisablePrimitiveTypeConversion overrides the lax mode behavior. // If there's no expected type, then there's nothing to validate against (open property). return expectedValueTypeReference != null && (!messageReaderSettings.DisableStrictMetadataValidation || useExpectedTypeOnlyForTypeResolution || (expectedValueTypeReference.IsODataPrimitiveTypeKind() && messageReaderSettings.DisablePrimitiveTypeConversion)); }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed when strict validation is enabled. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType) { // Strict validation logic switch (expectedTypeKind) { case EdmTypeKind.Complex: if (payloadType != null) { // The payload type must be compatible to the expected type. VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ true); // Use the payload type return payloadType.ToTypeReference(/*nullable*/ true); } break; case EdmTypeKind.Entity: if (payloadType != null) { // The payload type must be assignable to the expected type. IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)expectedTypeReference, (IEdmEntityTypeReference)payloadTypeReference); // Use the payload type return payloadTypeReference; } break; case EdmTypeKind.Enum: if (payloadType != null && string.CompareOrdinal(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()) != 0) { throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; case EdmTypeKind.Collection: // The type must be exactly equal - note that we intentionally ignore nullability of the items here, since the payload type // can't specify that. if (payloadType != null && !payloadType.IsElementTypeEquivalentTo(expectedTypeReference.Definition)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; case EdmTypeKind.TypeDefinition: if (payloadType != null && !expectedTypeReference.Definition.IsAssignableFrom(payloadType)) { throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal. return expectedTypeReference; }
/// <summary> /// Resolves the name of a primitive, complex, entity or collection type to the respective type. /// </summary> /// <param name="model">The model to use or null if no model is available.</param> /// <param name="expectedType">The expected type for the type name being resolved, or null if none is available.</param> /// <param name="typeName">The name of the type to resolve.</param> /// <param name="customTypeResolver">Custom type resolver to use, if null the model is used directly.</param> /// <param name="version">The version to use when resolving the type name.</param> /// <param name="typeKind">The type kind of the type, if it could be determined. This will be None if we couldn't tell. It might be filled /// even if the method returns null, for example for Collection types with item types which are not recognized.</param> /// <returns>The <see cref="IEdmType"/> representing the type specified by the <paramref name="typeName"/>; /// or null if no such type could be found.</returns> private static IEdmType ResolveTypeName( IEdmModel model, IEdmType expectedType, string typeName, Func<IEdmType, string, IEdmType> customTypeResolver, ODataVersion version, out EdmTypeKind typeKind) { Debug.Assert(model != null, "model != null"); Debug.Assert(typeName != null, "typeName != null"); IEdmType resolvedType = null; // Collection types should only be recognized in V3 and higher. string itemTypeName = version >= ODataVersion.V3 ? EdmLibraryExtensions.GetCollectionItemTypeName(typeName) : null; if (itemTypeName == null) { // Note: we require the type resolver or the model to also resolve // primitive types. if (customTypeResolver != null && model.IsUserModel()) { resolvedType = customTypeResolver(expectedType, typeName); if (resolvedType == null) { // If a type resolver is specified it must never return null. throw new ODataException(Strings.MetadataUtils_ResolveTypeName(typeName)); } } else { resolvedType = model.FindType(typeName); } // Spatial types are only recognized in V3 and higher. if (version < ODataVersion.V3 && resolvedType != null && resolvedType.IsSpatial()) { resolvedType = null; } typeKind = resolvedType == null ? EdmTypeKind.None : resolvedType.TypeKind; } else { // Collection typeKind = EdmTypeKind.Collection; EdmTypeKind itemTypeKind; IEdmType expectedItemType = null; if (customTypeResolver != null && expectedType != null && expectedType.TypeKind == EdmTypeKind.Collection) { expectedItemType = ((IEdmCollectionType)expectedType).ElementType.Definition; } IEdmType itemType = ResolveTypeName(model, expectedItemType, itemTypeName, customTypeResolver, version, out itemTypeKind); if (itemType != null) { resolvedType = EdmLibraryExtensions.GetCollectionType(itemType); } } return resolvedType; }