private object GetPropertyValue(IEdmTypeReference propertyType, object value) { if (value == null) { return(value); } switch (propertyType.TypeKind()) { case EdmTypeKind.Complex: var complexTypeProperties = propertyType.AsComplex().StructuralProperties(); return(new ODataComplexValue { TypeName = propertyType.FullName(), Properties = value.ToDictionary() .Where(val => complexTypeProperties.Any(p => p.Name == val.Key)) .Select(x => new ODataProperty { Name = x.Key, Value = GetPropertyValue(propertyType.AsComplex().StructuralProperties(), x.Key, x.Value), }) }); case EdmTypeKind.Collection: var collection = propertyType.AsCollection(); return(new ODataCollectionValue() { TypeName = propertyType.FullName(), Items = (value as IEnumerable <object>).Select(x => GetPropertyValue(collection.ElementType(), x)), }); case EdmTypeKind.Primitive: var mappedTypes = _typeMap.Where(x => x.Value == (propertyType.Definition as IEdmPrimitiveType).PrimitiveKind); if (mappedTypes.Any()) { foreach (var mappedType in mappedTypes) { object result; if (Utils.TryConvert(value, mappedType.Key, out result)) { return(result); } } throw new FormatException(string.Format("Unable to convert value of type {0} to OData type {1}", value.GetType(), propertyType)); } return(value); case EdmTypeKind.Enum: return(new ODataEnumValue(value.ToString())); default: return(value); } }
public override ODataSerializer CreateEdmTypeSerializer(IEdmTypeReference edmType) { if (edmType == null) { throw Error.ArgumentNull("edmType"); } switch (edmType.TypeKind()) { case EdmTypeKind.Primitive: return(new ODataPrimitiveSerializer(edmType.AsPrimitive())); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return(new ODataFeedSerializer(collectionType, this)); } else { return(new ODataCollectionSerializer(collectionType, this)); } case EdmTypeKind.Complex: return(new ODataComplexTypeSerializer(edmType.AsComplex(), this)); case EdmTypeKind.Entity: return(new ODataEntityTypeSerializer(edmType.AsEntity(), this)); default: throw Error.InvalidOperation(SRResources.TypeCannotBeSerialized, edmType.ToTraceString(), typeof(ODataMediaTypeFormatter).Name); } }
/// <summary> /// Validates that the expected property allows null value. /// </summary> /// <param name="expectedPropertyTypeReference">The expected property type or null if we don't have any.</param> /// <param name="propertyName">The name of the property.</param> /// <param name="model">The model to use to get the OData version.</param> internal static void ValidateNullPropertyValue(IEdmTypeReference expectedPropertyTypeReference, string propertyName, IEdmModel model) { Debug.Assert(model != null, "For null validation, model is required."); if (expectedPropertyTypeReference != null) { if (expectedPropertyTypeReference.IsNonEntityCollectionType()) { throw new ODataException(Strings.WriterValidationUtils_CollectionPropertiesMustNotHaveNullValue(propertyName)); } if (expectedPropertyTypeReference.IsODataPrimitiveTypeKind() && !expectedPropertyTypeReference.IsNullable) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.FullName())); } else if (expectedPropertyTypeReference.IsODataEnumTypeKind() && !expectedPropertyTypeReference.IsNullable) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.FullName())); } else if (expectedPropertyTypeReference.IsStream()) { throw new ODataException(Strings.WriterValidationUtils_StreamPropertiesMustNotHaveNullValue(propertyName)); } else if (expectedPropertyTypeReference.IsODataComplexTypeKind()) { IEdmComplexTypeReference complexTypeReference = expectedPropertyTypeReference.AsComplex(); if (!complexTypeReference.IsNullable) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.FullName())); } } } }
/// <summary> /// Constructs a new type reference with the specified nullable value /// </summary> /// <param name="typeReference">The original type reference</param> /// <param name="isNullable">The nullable value</param> /// <returns>A new type reference, with the specified nullable value</returns> public static IEdmTypeReference Nullable(this IEdmTypeReference typeReference, bool isNullable) { switch (typeReference.TypeKind()) { case EdmTypeKind.Collection: var collection = typeReference.AsCollection(); return(new EdmCollectionTypeReference(collection.CollectionDefinition())); case EdmTypeKind.Complex: var complex = typeReference.AsComplex(); return(new EdmComplexTypeReference(complex.ComplexDefinition(), isNullable)); case EdmTypeKind.Entity: var entity = typeReference.AsEntity(); return(new EdmEntityTypeReference(entity.EntityDefinition(), isNullable)); case EdmTypeKind.EntityReference: var entityRef = typeReference.AsEntityReference(); return(new EdmEntityReferenceTypeReference(entityRef.EntityReferenceDefinition(), isNullable)); case EdmTypeKind.Primitive: var primitive = (EdmPrimitiveTypeReference)typeReference.AsPrimitive(); return(primitive.Nullable(isNullable)); default: throw new TaupoInvalidOperationException("Unexpected Edm Type Kind: " + typeReference.TypeKind()); } }
public override ODataSerializer CreateEdmTypeSerializer(IEdmTypeReference edmType) { if (edmType == null) { throw Error.ArgumentNull("edmType"); } switch (edmType.TypeKind()) { case EdmTypeKind.Primitive: return new ODataPrimitiveSerializer(edmType.AsPrimitive()); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return new ODataFeedSerializer(collectionType, this); } else { return new ODataCollectionSerializer(collectionType, this); } case EdmTypeKind.Complex: return new ODataComplexTypeSerializer(edmType.AsComplex(), this); case EdmTypeKind.Entity: return new ODataEntityTypeSerializer(edmType.AsEntity(), this); default: throw Error.InvalidOperation(SRResources.TypeCannotBeSerialized, edmType.ToTraceString(), typeof(ODataMediaTypeFormatter).Name); } }
protected override ODataEntryDeserializer CreateDeserializer(IEdmTypeReference edmType) { if (edmType != null) { switch (edmType.TypeKind()) { case EdmTypeKind.Entity: return new ODataEntityDeserializer(edmType.AsEntity(), this); case EdmTypeKind.Primitive: return new ODataPrimitiveDeserializer(edmType.AsPrimitive()); case EdmTypeKind.Complex: return new ODataComplexTypeDeserializer(edmType.AsComplex(), this); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return new ODataFeedDeserializer(collectionType, this); } else { return new ODataCollectionDeserializer(collectionType, this); } } } return null; }
private static object ConvertComplexValue(ODataComplexValue complexValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmComplexTypeReference edmComplexType; if (propertyType == null) { // open complex property Contract.Assert(!String.IsNullOrEmpty(complexValue.TypeName), "ODataLib should have verified that open complex value has a type name since we provided metadata."); IEdmModel model = readContext.Model; IEdmType edmType = model.FindType(complexValue.TypeName); Contract.Assert(edmType.TypeKind == EdmTypeKind.Complex, "ODataLib should have verified that complex value has a complex resource type."); edmComplexType = new EdmComplexTypeReference(edmType as IEdmComplexType, isNullable: true); propertyType = edmComplexType; } else { edmComplexType = propertyType.AsComplex(); } ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(edmComplexType); return(deserializer.ReadInline(complexValue, propertyType, readContext)); }
/// <summary> /// Creates an <see cref="ODataEdmTypeDeserializer"/> that can deserialize payloads of the given <paramref name="edmType"/>. /// </summary> /// <param name="edmType">The EDM type that the created deserializer can handle.</param> /// <returns>The created deserializer.</returns> /// <remarks> Override this method if you want to use a custom deserializer. <see cref="GetEdmTypeDeserializer"/> calls into this method and caches the result.</remarks> public virtual ODataEdmTypeDeserializer CreateEdmTypeDeserializer(IEdmTypeReference edmType) { if (edmType == null) { throw Error.ArgumentNull("edmType"); } switch (edmType.TypeKind()) { case EdmTypeKind.Entity: return(new ODataEntityDeserializer(edmType.AsEntity(), this)); case EdmTypeKind.Primitive: return(new ODataPrimitiveDeserializer(edmType.AsPrimitive())); case EdmTypeKind.Complex: return(new ODataComplexTypeDeserializer(edmType.AsComplex(), this)); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return(new ODataFeedDeserializer(collectionType, this)); } else { return(new ODataCollectionDeserializer(collectionType, this)); } default: return(null); } }
/// <inheritdoc /> public sealed override object ReadInline(object item, IEdmTypeReference edmType, ODataDeserializerContext readContext) { if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (item == null) { return(null); } ODataComplexValue complexValue = item as ODataComplexValue; if (complexValue == null) { throw Error.Argument("item", SRResources.ArgumentMustBeOfType, typeof(ODataComplexValue).Name); } if (!edmType.IsComplex()) { throw Error.Argument("edmType", SRResources.ArgumentMustBeOfType, EdmTypeKind.Complex); } // Recursion guard to avoid stack overflows RuntimeHelpers.EnsureSufficientExecutionStack(); return(ReadComplexValue(complexValue, edmType.AsComplex(), readContext)); }
/// <summary> /// Creates a new instance of the <see cref="ODataEntrySerializer"/> for the given edm type. /// </summary> /// <param name="edmType">The <see cref="IEdmTypeReference"/>.</param> /// <returns>The constructed <see cref="ODataEntrySerializer"/>.</returns> public virtual ODataEntrySerializer CreateEdmTypeSerializer(IEdmTypeReference edmType) { if (edmType == null) { throw Error.ArgumentNull("edmType"); } switch (edmType.TypeKind()) { case EdmTypeKind.Primitive: return new ODataPrimitiveSerializer(edmType.AsPrimitive()); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return new ODataFeedSerializer(collectionType, this); } else { return new ODataCollectionSerializer(collectionType, this); } case EdmTypeKind.Complex: return new ODataComplexTypeSerializer(edmType.AsComplex(), this); case EdmTypeKind.Entity: return new ODataEntityTypeSerializer(edmType.AsEntity(), this); default: return null; } }
/// <summary> /// If this reference is of a structured type, this will return a valid structured type reference to the type definition. Otherwise, it will return a bad structured type reference. /// </summary> /// <param name="type">Reference to the calling object.</param> /// <returns>A valid structured type reference if the definition of the reference is of a structured type. Otherwise a bad structured type reference.</returns> public static IEdmStructuredTypeReference AsStructured(this IEdmTypeReference type) { EdmUtil.CheckArgumentNull(type, "type"); IEdmStructuredTypeReference reference = type as IEdmStructuredTypeReference; if (reference != null) { return(reference); } switch (type.TypeKind()) { case EdmTypeKind.Entity: return(type.AsEntity()); case EdmTypeKind.Complex: return(type.AsComplex()); } string typeFullName = type.FullName(); List <EdmError> errors = new List <EdmError>(type.TypeErrors()); if (errors.Count == 0) { errors.AddRange(ConversionError(type.Location(), typeFullName, EdmConstants.Type_Structured)); } return(new BadEntityTypeReference(typeFullName, type.IsNullable, errors)); }
/// <inheritdoc /> public sealed override object ReadInline(object item, IEdmTypeReference edmType, ODataDeserializerContext readContext) { if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (item == null) { return null; } ODataComplexValue complexValue = item as ODataComplexValue; if (complexValue == null) { throw Error.Argument("item", SRResources.ArgumentMustBeOfType, typeof(ODataComplexValue).Name); } if (!edmType.IsComplex()) { throw Error.Argument("edmType", SRResources.ArgumentMustBeOfType, EdmTypeKind.Complex); } // Recursion guard to avoid stack overflows RuntimeHelpers.EnsureSufficientExecutionStack(); return ReadComplexValue(complexValue, edmType.AsComplex(), readContext); }
protected override ODataEntryDeserializer CreateDeserializer(IEdmTypeReference edmType) { if (edmType != null) { switch (edmType.TypeKind()) { case EdmTypeKind.Entity: return(new ODataEntityDeserializer(edmType.AsEntity(), this)); case EdmTypeKind.Primitive: return(new ODataPrimitiveDeserializer(edmType.AsPrimitive())); case EdmTypeKind.Complex: return(new ODataComplexTypeDeserializer(edmType.AsComplex(), this)); case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionType = edmType.AsCollection(); if (collectionType.ElementType().IsEntity()) { return(new ODataFeedDeserializer(collectionType, this)); } else { return(new ODataCollectionDeserializer(collectionType, this)); } } } return(null); }
internal static object ConvertTo(ODataParameterValue parameterValue, HttpActionContext actionContext, ModelBindingContext bindingContext) { Contract.Assert(parameterValue != null && parameterValue.EdmType != null); object oDataValue = parameterValue.Value; if (oDataValue == null || oDataValue is ODataNullValue) { return(null); } IEdmTypeReference edmTypeReference = parameterValue.EdmType; ODataDeserializerContext readContext = BuildDeserializerContext(actionContext, bindingContext, edmTypeReference); // complex value ODataComplexValue complexValue = oDataValue as ODataComplexValue; if (complexValue != null) { IEdmComplexTypeReference edmComplexType = edmTypeReference.AsComplex(); Contract.Assert(edmComplexType != null); ODataComplexTypeDeserializer deserializer = (ODataComplexTypeDeserializer)DeserializerProvider.GetEdmTypeDeserializer(edmComplexType); return(deserializer.ReadInline(complexValue, edmComplexType, readContext)); } // collection of primitive, enum, complex ODataCollectionValue collectionValue = oDataValue as ODataCollectionValue; if (collectionValue != null) { return(ConvertCollection(collectionValue, edmTypeReference, bindingContext, readContext)); } // enum value ODataEnumValue enumValue = oDataValue as ODataEnumValue; if (enumValue != null) { IEdmEnumTypeReference edmEnumType = edmTypeReference.AsEnum(); Contract.Assert(edmEnumType != null); ODataEnumDeserializer deserializer = (ODataEnumDeserializer)DeserializerProvider.GetEdmTypeDeserializer(edmEnumType); return(deserializer.ReadInline(enumValue, edmEnumType, readContext)); } // primitive value if (edmTypeReference.IsPrimitive()) { return(EdmPrimitiveHelpers.ConvertPrimitiveValue(oDataValue, bindingContext.ModelType)); } // Entity, Feed, Entity Reference or collection of entity reference return(ConvertFeedOrEntry(oDataValue, edmTypeReference, readContext)); }
internal static object ConvertValue( object odataValue, Type expectedReturnType, IEdmTypeReference propertyType, IEdmModel model, ApiContext apiContext) { ODataDeserializerContext readContext = new ODataDeserializerContext { Model = model }; ODataDeserializerProvider deserializerProvider = apiContext.GetApiService <ODataDeserializerProvider>(); if (odataValue == null) { return(null); } ODataNullValue nullValue = odataValue as ODataNullValue; if (nullValue != null) { return(null); } ODataComplexValue complexValue = odataValue as ODataComplexValue; if (complexValue != null) { ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(propertyType.AsComplex()); return(deserializer.ReadInline(complexValue, propertyType, readContext)); } ODataEnumValue enumValue = odataValue as ODataEnumValue; if (enumValue != null) { ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(propertyType.AsEnum()); return(deserializer.ReadInline(enumValue, propertyType, readContext)); } ODataCollectionValue collection = odataValue as ODataCollectionValue; if (collection != null) { ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(propertyType as IEdmCollectionTypeReference); var collectionResult = deserializer.ReadInline(collection, propertyType, readContext); return(ConvertCollectionType(collectionResult, expectedReturnType)); } return(odataValue); }
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 IEdmComplexTypeReference AsComplexOrNull(this IEdmTypeReference typeReference) { if (typeReference == null) { return(null); } if (typeReference.TypeKind() != EdmTypeKind.Complex) { return(null); } return(typeReference.AsComplex()); }
private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue) { object obj2; SerializationTypeNameAnnotation annotation; EdmTypeKind kind; JsonNodeType nodeType = base.JsonReader.NodeType; if (nodeType == JsonNodeType.StartArray) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType)); } if (this.TryReadNullValue(expectedTypeReference, validateNullValue)) { return(null); } string payloadTypeName = this.FindTypeNameInPayload(); IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, null, expectedTypeReference, payloadTypeName, base.Model, base.MessageReaderSettings, base.Version, new Func <EdmTypeKind>(this.GetNonEntityValueKind), out kind, out annotation); switch (kind) { case EdmTypeKind.Primitive: { IEdmPrimitiveTypeReference reference2 = (type == null) ? null : type.AsPrimitive(); if ((payloadTypeName != null) && !reference2.IsSpatial()) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName)); } obj2 = this.ReadPrimitiveValueImplementation(reference2, validateNullValue); break; } case EdmTypeKind.Complex: obj2 = this.ReadComplexValueImplementation((type == null) ? null : type.AsComplex(), payloadTypeName, annotation, duplicatePropertyNamesChecker); break; case EdmTypeKind.Collection: { IEdmCollectionTypeReference collectionValueTypeReference = ValidationUtils.ValidateCollectionType(type); obj2 = this.ReadCollectionValueImplementation(collectionValueTypeReference, payloadTypeName, annotation); break; } default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataJsonPropertyAndValueDeserializer_ReadPropertyValue)); } if (collectionValidator != null) { string collectionItemTypeName = ODataJsonReaderUtils.GetPayloadTypeName(obj2); collectionValidator.ValidateCollectionItem(collectionItemTypeName, kind); } return(obj2); }
private static bool HasAutoExpandProperty(this IEdmModel edmModel, IEdmStructuredType structuredType, IEdmProperty pathProperty, ISet <IEdmStructuredType> visited) { if (visited.Contains(structuredType)) { return(false); } visited.Add(structuredType); List <IEdmStructuredType> structuredTypes = new List <IEdmStructuredType>(); structuredTypes.Add(structuredType); structuredTypes.AddRange(edmModel.FindAllDerivedTypes(structuredType)); foreach (IEdmStructuredType edmStructuredType in structuredTypes) { // for top type, let's retrieve its properties and the properties from base type of top type if has. // for derived type, let's retrieve the declared properties. IEnumerable <IEdmProperty> properties = edmStructuredType == structuredType ? edmStructuredType.Properties() : edmStructuredType.DeclaredProperties; foreach (IEdmProperty property in properties) { switch (property.PropertyKind) { case EdmPropertyKind.Structural: IEdmStructuralProperty structuralProperty = (IEdmStructuralProperty)property; IEdmTypeReference typeRef = property.Type.GetElementTypeOrSelf(); if (typeRef.IsComplex() && edmModel.CanExpand(typeRef.AsComplex().ComplexDefinition(), structuralProperty)) { IEdmStructuredType subStrucutredType = typeRef.AsStructured().StructuredDefinition(); if (edmModel.HasAutoExpandProperty(subStrucutredType, structuralProperty, visited)) { return(true); } } break; case EdmPropertyKind.Navigation: IEdmNavigationProperty navigationProperty = (IEdmNavigationProperty)property; if (IsAutoExpand(navigationProperty, pathProperty, edmStructuredType, edmModel)) { return(true); // find an auto-expand navigation property path } break; } } } return(false); }
public void VisitTypeReference(IEdmTypeReference reference) { switch (reference.TypeKind()) { case EdmTypeKind.Collection: this.ProcessCollectionTypeReference(reference.AsCollection()); break; case EdmTypeKind.Complex: this.ProcessComplexTypeReference(reference.AsComplex()); break; case EdmTypeKind.Entity: this.ProcessEntityTypeReference(reference.AsEntity()); break; case EdmTypeKind.EntityReference: this.ProcessEntityReferenceTypeReference(reference.AsEntityReference()); break; case EdmTypeKind.Enum: this.ProcessEnumTypeReference(reference.AsEnum()); break; case EdmTypeKind.Primitive: this.VisitPrimitiveTypeReference(reference.AsPrimitive()); break; case EdmTypeKind.TypeDefinition: this.ProcessTypeDefinitionReference(reference.AsTypeDefinition()); break; case EdmTypeKind.None: this.ProcessTypeReference(reference); break; case EdmTypeKind.Path: this.ProcessPathTypeReference(reference.AsPath()); break; case EdmTypeKind.Untyped: this.ProcessUntypedTypeReference(reference as IEdmUntypedTypeReference); break; default: throw new InvalidOperationException(Edm.Strings.UnknownEnumVal_TypeKind(reference.TypeKind().ToString())); } }
/// <inheitdoc /> public sealed override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext) { if (expectedType == null) { throw Error.ArgumentNull("expectedType"); } if (!expectedType.IsComplex()) { throw new SerializationException( Error.Format(SRResources.CannotWriteType, GetType().Name, expectedType.FullName())); } return(CreateODataComplexValue(graph, expectedType.AsComplex(), writeContext)); }
/// <inheitdoc /> public sealed override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext) { if (expectedType == null) { throw Error.ArgumentNull("expectedType"); } if (!expectedType.IsComplex()) { throw new SerializationException( Error.Format(SRResources.CannotWriteType, GetType().Name, expectedType.FullName())); } return CreateODataComplexValue(graph, expectedType.AsComplex(), writeContext); }
/// <summary> /// Validates that the expected property allows null value. /// </summary> /// <param name="expectedPropertyTypeReference">The expected property type or null if we don't have any.</param> /// <param name="propertyName">The name of the property.</param> /// <param name="writerBehavior">The <see cref="ODataWriterBehavior"/> instance controlling the behavior of the writer.</param> /// <param name="model">The model to use to get the OData version.</param> /// <param name="bypassValidation">Bypass the validation if it is true.</param> internal static void ValidateNullPropertyValue(IEdmTypeReference expectedPropertyTypeReference, string propertyName, ODataWriterBehavior writerBehavior, IEdmModel model, bool bypassValidation = false) { Debug.Assert(writerBehavior != null, "writerBehavior != null"); Debug.Assert(model != null, "For null validation, model is required."); if (bypassValidation) { return; } if (expectedPropertyTypeReference != null) { if (expectedPropertyTypeReference.IsNonEntityCollectionType()) { throw new ODataException(Strings.WriterValidationUtils_CollectionPropertiesMustNotHaveNullValue(propertyName)); } if (expectedPropertyTypeReference.IsODataPrimitiveTypeKind()) { // WCF DS allows null values for non-nullable primitive types, so we need to check for a knob which enables this behavior. // See the description of ODataWriterBehavior.AllowNullValuesForNonNullablePrimitiveTypes for more details. if (!expectedPropertyTypeReference.IsNullable && !writerBehavior.AllowNullValuesForNonNullablePrimitiveTypes) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.ODataFullName())); } } else if (expectedPropertyTypeReference.IsODataEnumTypeKind() && !expectedPropertyTypeReference.IsNullable) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.ODataFullName())); } else if (expectedPropertyTypeReference.IsStream()) { throw new ODataException(Strings.WriterValidationUtils_StreamPropertiesMustNotHaveNullValue(propertyName)); } else if (expectedPropertyTypeReference.IsODataComplexTypeKind()) { if (ValidationUtils.ShouldValidateComplexPropertyNullValue(model)) { IEdmComplexTypeReference complexTypeReference = expectedPropertyTypeReference.AsComplex(); if (!complexTypeReference.IsNullable) { throw new ODataException(Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(propertyName, expectedPropertyTypeReference.ODataFullName())); } } } } }
public static IEdmStructuredTypeReference AsStructured(this IEdmTypeReference type) { string str; List <EdmError> edmErrors; EdmUtil.CheckArgumentNull <IEdmTypeReference>(type, "type"); IEdmStructuredTypeReference edmStructuredTypeReference = type as IEdmStructuredTypeReference; if (edmStructuredTypeReference == null) { EdmTypeKind edmTypeKind = type.TypeKind(); switch (edmTypeKind) { case EdmTypeKind.Entity: { return(type.AsEntity()); } case EdmTypeKind.Complex: { return(type.AsComplex()); } case EdmTypeKind.Row: { return(type.AsRow()); } default: { str = type.FullName(); edmErrors = new List <EdmError>(type.TypeErrors()); if (edmErrors.Count != 0) { break; } edmErrors.AddRange(EdmTypeSemantics.ConversionError(type.Location(), str, "Structured")); break; } } return(new BadEntityTypeReference(str, type.IsNullable, edmErrors)); } else { return(edmStructuredTypeReference); } }
private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent) { string itemTypeNameFromCollection; bool flag; SerializationTypeNameAnnotation annotation; EdmTypeKind kind2; this.ReadNonEntityValueAttributes(out itemTypeNameFromCollection, out flag); if (flag) { return(this.ReadNullValue(expectedTypeReference, validateNullValue)); } bool flag2 = false; if ((collectionValidator != null) && (itemTypeNameFromCollection == null)) { itemTypeNameFromCollection = collectionValidator.ItemTypeNameFromCollection; flag2 = collectionValidator.ItemTypeKindFromCollection != EdmTypeKind.None; } IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, edmStringType, expectedTypeReference, itemTypeNameFromCollection, base.Model, base.MessageReaderSettings, base.Version, new Func <EdmTypeKind>(this.GetNonEntityValueKind), out kind2, out annotation); if (flag2) { annotation = new SerializationTypeNameAnnotation { TypeName = null }; } if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(itemTypeNameFromCollection, kind2); } switch (kind2) { case EdmTypeKind.Primitive: return(this.ReadPrimitiveValue(type.AsPrimitive())); case EdmTypeKind.Complex: return(this.ReadComplexValue((type == null) ? null : type.AsComplex(), itemTypeNameFromCollection, annotation, duplicatePropertyNamesChecker, epmPresent)); case EdmTypeKind.Collection: { IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(type); return(this.ReadCollectionValue(collectionTypeReference, itemTypeNameFromCollection, annotation)); } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue)); }
private DataType ConvertToTaupoDataType(IEdmTypeReference edmTypeReference) { EdmTypeKind kind = edmTypeReference.TypeKind(); if (kind == EdmTypeKind.Collection) { var elementEdmTypeReference = edmTypeReference.AsCollection().ElementType(); return(DataTypes.CollectionType .WithElementDataType(this.ConvertToTaupoDataType(elementEdmTypeReference)) .Nullable(edmTypeReference.IsNullable)); } else if (kind == EdmTypeKind.Complex) { var complexEdmTypeDefinition = edmTypeReference.AsComplex().ComplexDefinition(); return(DataTypes.ComplexType .WithName(complexEdmTypeDefinition.Namespace, complexEdmTypeDefinition.Name) .Nullable(edmTypeReference.IsNullable)); } else if (kind == EdmTypeKind.Entity) { var entityEdmTypeDefinition = edmTypeReference.AsEntity().EntityDefinition(); return(DataTypes.EntityType .WithName(entityEdmTypeDefinition.Namespace, entityEdmTypeDefinition.Name) .Nullable(edmTypeReference.IsNullable)); } else if (kind == EdmTypeKind.EntityReference) { var entityEdmTypeDefinition = edmTypeReference.AsEntityReference().EntityType(); return(DataTypes.ReferenceType .WithEntityType(new EntityTypeReference(entityEdmTypeDefinition.Namespace, entityEdmTypeDefinition.Name)) .Nullable(edmTypeReference.IsNullable)); } else if (kind == EdmTypeKind.Primitive) { return(EdmToTaupoPrimitiveDataTypeConverter.ConvertToTaupoPrimitiveDataType(edmTypeReference.AsPrimitive())); } else if (kind == EdmTypeKind.Enum) { var enumTypeDefinition = edmTypeReference.AsEnum().EnumDefinition(); return(DataTypes.EnumType.WithName(enumTypeDefinition.Namespace, enumTypeDefinition.Name)); } throw new TaupoInvalidOperationException("unexpected Edm Type Kind: " + kind); }
protected override ODataEntryDeserializer CreateDeserializer(IEdmTypeReference edmType) { if (edmType != null) { switch (edmType.TypeKind()) { case EdmTypeKind.Entity: return(new ODataEntityDeserializer(edmType.AsEntity(), this)); case EdmTypeKind.Primitive: return(new ODataRawValueDeserializer(edmType.AsPrimitive())); case EdmTypeKind.Complex: return(new ODataComplexTypeDeserializer(edmType.AsComplex(), this)); } } return(null); }
protected override ODataEntryDeserializer CreateDeserializer(IEdmTypeReference edmType) { if (edmType != null) { switch (edmType.TypeKind()) { case EdmTypeKind.Entity: return new ODataEntityDeserializer(edmType.AsEntity(), this); case EdmTypeKind.Primitive: return new ODataRawValueDeserializer(edmType.AsPrimitive()); case EdmTypeKind.Complex: return new ODataComplexTypeDeserializer(edmType.AsComplex(), this); } } return null; }
/// <summary> /// Gets property for dynamic properties dictionary. /// </summary> /// <param name="openNode"></param> /// <returns>Returns CLR property for dynamic properties container.</returns> protected PropertyInfo GetDynamicPropertyContainer(SingleValueOpenPropertyAccessNode openNode) { IEdmStructuredType edmStructuredType; IEdmTypeReference edmTypeReference = openNode.Source.TypeReference; if (edmTypeReference.IsEntity()) { edmStructuredType = edmTypeReference.AsEntity().EntityDefinition(); } else if (edmTypeReference.IsComplex()) { edmStructuredType = edmTypeReference.AsComplex().ComplexDefinition(); } else { throw Error.NotSupported(SRResources.QueryNodeBindingNotSupported, openNode.Kind, typeof(FilterBinder).Name); } return(EdmLibHelpers.GetDynamicPropertyDictionary(edmStructuredType, Model)); }
private MetaType GetOrBuildType(IEdmTypeReference edmTypeReference) { switch (edmTypeReference.TypeKind()) { case EdmTypeKind.Primitive: VisitPrimitiveTypeReference(edmTypeReference.AsPrimitive()); break; case EdmTypeKind.Entity: VisitEntityType(edmTypeReference.AsEntity().EntityDefinition()); break; case EdmTypeKind.Complex: VisitComplexType(edmTypeReference.AsComplex().ComplexDefinition()); break; case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionTypeRef = edmTypeReference.AsCollection(); return(GetOrBuildType(collectionTypeRef.ElementType())); case EdmTypeKind.Enum: VisitEnumType(edmTypeReference.AsEnum().EnumDefinition()); break; case EdmTypeKind.TypeDefinition: VisitTypeDefinition(edmTypeReference.AsTypeDefinition().TypeDefinition()); break; case EdmTypeKind.Path: VisitPathType(edmTypeReference.AsPath()); break; case EdmTypeKind.EntityReference: case EdmTypeKind.None: case EdmTypeKind.Untyped: default: throw new InvalidOperationException($"Found an unknow type kind '{edmTypeReference.TypeKind()}'"); } return(_types[edmTypeReference.FullName()]); }
private object GetPropertyValue(IEdmTypeReference propertyType, object value) { if (value == null) { return(value); } switch (propertyType.TypeKind()) { case EdmTypeKind.Complex: if (CustomConverters.HasObjectConverter(value.GetType())) { return(CustomConverters.Convert(value, value.GetType())); } var complexTypeProperties = propertyType.AsComplex().StructuralProperties(); return(new ODataComplexValue { TypeName = propertyType.FullName(), Properties = value.ToDictionary(TypeCache) .Where(val => complexTypeProperties.Any(p => p.Name == val.Key)) .Select(x => new ODataProperty { Name = x.Key, Value = GetPropertyValue(complexTypeProperties, x.Key, x.Value), }) }); case EdmTypeKind.Collection: var collection = propertyType.AsCollection(); return(new ODataCollectionValue() { TypeName = propertyType.FullName(), Items = ((IEnumerable)value).Cast <object>().Select(x => GetPropertyValue(collection.ElementType(), x)), }); case EdmTypeKind.Primitive: var mappedTypes = _typeMap.Where(x => x.Value == (propertyType.Definition as IEdmPrimitiveType).PrimitiveKind); if (mappedTypes.Any()) { foreach (var mappedType in mappedTypes) { if (TypeCache.TryConvert(value, mappedType.Key, out var result)) { return(result); } } throw new NotSupportedException($"Conversion is not supported from type {value.GetType()} to OData type {propertyType}"); } return(value); case EdmTypeKind.Enum: return(value.ToString()); case EdmTypeKind.None: if (CustomConverters.HasObjectConverter(value.GetType())) { return(CustomConverters.Convert(value, value.GetType())); } throw new NotSupportedException($"Conversion is not supported from type {value.GetType()} to OData type {propertyType}"); default: return(value); } }
private static void ValidateNullValueAllowed(IEdmTypeReference expectedValueTypeReference, bool validateNullValue, IEdmModel model) { if (validateNullValue && (expectedValueTypeReference != null)) { if (expectedValueTypeReference.IsODataPrimitiveTypeKind()) { if (!expectedValueTypeReference.IsNullable) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } } else { if (expectedValueTypeReference.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } if ((expectedValueTypeReference.IsODataComplexTypeKind() && ValidationUtils.ShouldValidateComplexPropertyNullValue(model)) && !expectedValueTypeReference.AsComplex().IsNullable) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } } } }
private static object ConvertComplexValue(ODataComplexValue complexValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmComplexTypeReference complexTypeReference = propertyType != null?propertyType.AsComplex() : (IEdmComplexTypeReference) new EdmComplexTypeReference((IEdmType)readContext.Model.FindType(complexValue.TypeName) as IEdmComplexType, true); return(deserializerProvider.GetEdmTypeDeserializer((IEdmTypeReference)complexTypeReference).ReadInline((object)complexValue, propertyType, readContext)); }
/// <summary> /// Validates that the specified <paramref name="expectedValueTypeReference"/> allows null values. /// </summary> /// <param name="expectedValueTypeReference">The expected type for the value, or null if no such type is available.</param> /// <param name="validateNullValue">true to validate the null value; otherwise false.</param> /// <param name="model">The model to use to get the data service version.</param> private static void ValidateNullValueAllowed(IEdmTypeReference expectedValueTypeReference, bool validateNullValue, IEdmModel model) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(model != null, "For null validation, model is required."); if (validateNullValue && expectedValueTypeReference != null) { Debug.Assert( expectedValueTypeReference.IsODataPrimitiveTypeKind() || expectedValueTypeReference.IsODataComplexTypeKind() || expectedValueTypeReference.IsNonEntityODataCollectionTypeKind(), "Only primitive, complex and collection types are supported by this method."); if (expectedValueTypeReference.IsODataPrimitiveTypeKind()) { if (!expectedValueTypeReference.IsNullable) { throw new ODataException(Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } } else if (expectedValueTypeReference.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } else if (expectedValueTypeReference.IsODataComplexTypeKind()) { if (ValidationUtils.ShouldValidateComplexPropertyNullValue(model)) { IEdmComplexTypeReference complexTypeReference = expectedValueTypeReference.AsComplex(); if (!complexTypeReference.IsNullable) { throw new ODataException(Strings.ReaderValidationUtils_NullValueForNonNullableType(expectedValueTypeReference.ODataFullName())); } } } } }
internal static void ValidateNullPropertyValue(IEdmProperty expectedProperty, ODataWriterBehavior writerBehavior, IEdmModel model) { if (expectedProperty != null) { IEdmTypeReference type = expectedProperty.Type; if (type.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.WriterValidationUtils_CollectionPropertiesMustNotHaveNullValue(expectedProperty.Name)); } if (type.IsODataPrimitiveTypeKind()) { if (!type.IsNullable && !writerBehavior.AllowNullValuesForNonNullablePrimitiveTypes) { throw new ODataException(Microsoft.Data.OData.Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(expectedProperty.Name, expectedProperty.Type.ODataFullName())); } } else { if (type.IsStream()) { throw new ODataException(Microsoft.Data.OData.Strings.WriterValidationUtils_StreamPropertiesMustNotHaveNullValue(expectedProperty.Name)); } if ((type.IsODataComplexTypeKind() && ValidationUtils.ShouldValidateComplexPropertyNullValue(model)) && !type.AsComplex().IsNullable) { throw new ODataException(Microsoft.Data.OData.Strings.WriterValidationUtils_NonNullablePropertiesMustNotHaveNullValue(expectedProperty.Name, expectedProperty.Type.ODataFullName())); } } } }
private DataType ConvertToTaupoDataType(IEdmTypeReference edmTypeReference) { EdmTypeKind kind = edmTypeReference.TypeKind(); if (kind == EdmTypeKind.Collection) { var elementEdmTypeReference = edmTypeReference.AsCollection().ElementType(); return DataTypes.CollectionType .WithElementDataType(this.ConvertToTaupoDataType(elementEdmTypeReference)) .Nullable(edmTypeReference.IsNullable); } else if (kind == EdmTypeKind.Complex) { var complexEdmTypeDefinition = edmTypeReference.AsComplex().ComplexDefinition(); return DataTypes.ComplexType .WithName(complexEdmTypeDefinition.Namespace, complexEdmTypeDefinition.Name) .Nullable(edmTypeReference.IsNullable); } else if (kind == EdmTypeKind.Entity) { var entityEdmTypeDefinition = edmTypeReference.AsEntity().EntityDefinition(); return DataTypes.EntityType .WithName(entityEdmTypeDefinition.Namespace, entityEdmTypeDefinition.Name) .Nullable(edmTypeReference.IsNullable); } else if (kind == EdmTypeKind.EntityReference) { var entityEdmTypeDefinition = edmTypeReference.AsEntityReference().EntityType(); return DataTypes.ReferenceType .WithEntityType(new EntityTypeReference(entityEdmTypeDefinition.Namespace, entityEdmTypeDefinition.Name)) .Nullable(edmTypeReference.IsNullable); } else if (kind == EdmTypeKind.Primitive) { return EdmToTaupoPrimitiveDataTypeConverter.ConvertToTaupoPrimitiveDataType(edmTypeReference.AsPrimitive()); } else if (kind == EdmTypeKind.Enum) { var enumTypeDefinition = edmTypeReference.AsEnum().EnumDefinition(); return DataTypes.EnumType.WithName(enumTypeDefinition.Namespace, enumTypeDefinition.Name); } throw new TaupoInvalidOperationException("unexpected Edm Type Kind: " + kind); }
private object GetPropertyValue(IEdmTypeReference propertyType, object value) { if (value == null) return value; switch (propertyType.TypeKind()) { case EdmTypeKind.Complex: var complexTypeProperties = propertyType.AsComplex().StructuralProperties(); return new ODataComplexValue { TypeName = propertyType.FullName(), Properties = value.ToDictionary() .Where(val => complexTypeProperties.Any(p => p.Name == val.Key)) .Select(x => new ODataProperty { Name = x.Key, Value = GetPropertyValue(complexTypeProperties, x.Key, x.Value), }) }; case EdmTypeKind.Collection: var collection = propertyType.AsCollection(); return new ODataCollectionValue() { TypeName = propertyType.FullName(), Items = (value as IEnumerable<object>).Select(x => GetPropertyValue(collection.ElementType(), x)), }; case EdmTypeKind.Primitive: var mappedTypes = _typeMap.Where(x => x.Value == (propertyType.Definition as IEdmPrimitiveType).PrimitiveKind); if (mappedTypes.Any()) { foreach (var mappedType in mappedTypes) { object result; if (Utils.TryConvert(value, mappedType.Key, out result)) return result; } throw new NotSupportedException(string.Format("Conversion is not supported from type {0} to OData type {1}", value.GetType(), propertyType)); } return value; case EdmTypeKind.Enum: return new ODataEnumValue(value.ToString()); case EdmTypeKind.None: if (CustomConverters.HasObjectConverter(value.GetType())) { return CustomConverters.Convert(value, value.GetType()); } throw new NotSupportedException(string.Format("Conversion is not supported from type {0} to OData type {1}", value.GetType(), propertyType)); default: return value; } }
private static object ConvertComplexValue(ODataComplexValue complexValue, ref IEdmTypeReference propertyType, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmComplexTypeReference edmComplexType; if (propertyType == null) { // open complex property Contract.Assert(!String.IsNullOrEmpty(complexValue.TypeName), "ODataLib should have verified that open complex value has a type name since we provided metadata."); IEdmModel model = readContext.Model; IEdmType edmType = model.FindType(complexValue.TypeName); Contract.Assert(edmType.TypeKind == EdmTypeKind.Complex, "ODataLib should have verified that complex value has a complex resource type."); edmComplexType = new EdmComplexTypeReference(edmType as IEdmComplexType, isNullable: true); propertyType = edmComplexType; } else { edmComplexType = propertyType.AsComplex(); } ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(edmComplexType); return deserializer.ReadInline(complexValue, propertyType, readContext); }
private object GetPropertyValue(IEdmTypeReference propertyType, object value) { if (value == null) return value; switch (propertyType.TypeKind()) { case EdmTypeKind.Complex: return new ODataComplexValue() { TypeName = propertyType.FullName(), Properties = value.ToDictionary().Select(x => new ODataProperty() { Name = x.Key, Value = GetPropertyValue(propertyType.AsComplex().StructuralProperties(), x.Key, x.Value), }), }; case EdmTypeKind.Collection: var collection = propertyType.AsCollection(); return new ODataCollectionValue() { TypeName = propertyType.FullName(), Items = (value as IEnumerable<object>).Select(x => GetPropertyValue(collection.ElementType(), x)), }; case EdmTypeKind.Primitive: var mappedTypes = _typeMap.Where(x => x.Value == (propertyType.Definition as IEdmPrimitiveType).PrimitiveKind); if (mappedTypes.Any()) { foreach (var mappedType in mappedTypes) { object result; if (Utils.TryConvert(value, mappedType.Key, out result)) return result; } throw new FormatException(string.Format("Unable to convert value of type {0} to OData type {1}", value.GetType(), propertyType)); } return value; case EdmTypeKind.Enum: return new ODataEnumValue(value.ToString()); default: return value; } }
/// <summary> /// Reads a primitive, complex or collection value. /// </summary> /// <param name="expectedTypeReference">The expected type reference of the property value.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param> /// <param name="validateNullValue">true to validate null values; otherwise false.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable.</param> /// <returns>The value of the property read.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.PrimitiveValue - the value of the property is a primitive value /// JsonNodeType.StartObject - the value of the property is an object /// JsonNodeType.StartArray - the value of the property is an array - method will fail in this case. /// Post-Condition: almost anything - the node after the property value. /// /// Returns the value of the property read, which can be one of: /// - null /// - primitive value /// - <see cref="ODataComplexValue"/> /// - <see cref="ODataCollectionValue"/> /// </remarks> private object ReadNonEntityValueImplementation( IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, string propertyName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert( this.JsonReader.NodeType == JsonNodeType.PrimitiveValue || this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray, "Pre-Condition: expected JsonNodeType.PrimitiveValue or JsonNodeType.StartObject or JsonNodeType.StartArray"); Debug.Assert( expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(), "Only primitive, complex or collection types can be read by this method."); Debug.Assert( expectedTypeReference == null || collectionValidator == null, "If an expected value type reference is specified, no collection validator must be provided."); this.JsonReader.AssertNotBuffering(); // Property values can be only primitives or objects. No property can have a JSON array value. JsonNodeType nodeType = this.JsonReader.NodeType; if (nodeType == JsonNodeType.StartArray) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType)); } // Try to read a null value object result; if (ODataJsonReaderCoreUtils.TryReadNullValue( this.JsonReader, this.VerboseJsonInputContext, expectedTypeReference, validateNullValue, propertyName)) { result = null; } else { // Read the payload type name string payloadTypeName = this.FindTypeNameInPayload(); SerializationTypeNameAnnotation serializationTypeNameAnnotation; EdmTypeKind targetTypeKind; IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind.None, /*defaultPrimitivePayloadType*/ null, expectedTypeReference, payloadTypeName, this.Model, this.MessageReaderSettings, this.Version, this.GetNonEntityValueKind, out targetTypeKind, out serializationTypeNameAnnotation); switch (targetTypeKind) { case EdmTypeKind.Primitive: Debug.Assert(targetTypeReference == null || targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type."); IEdmPrimitiveTypeReference primitiveTargetTypeReference = targetTypeReference == null ? null : targetTypeReference.AsPrimitive(); if (payloadTypeName != null && !primitiveTargetTypeReference.IsSpatial()) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName)); } result = this.ReadPrimitiveValue( primitiveTargetTypeReference, validateNullValue, propertyName); break; case EdmTypeKind.Complex: Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type."); result = this.ReadComplexValueImplementation( targetTypeReference == null ? null : targetTypeReference.AsComplex(), payloadTypeName, serializationTypeNameAnnotation, duplicatePropertyNamesChecker); break; case EdmTypeKind.Collection: Debug.Assert(this.Version >= ODataVersion.V3, "Type resolution should already fail if we would decide to read a collection value in V1/V2 payload."); IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference); result = this.ReadCollectionValueImplementation( collectionTypeReference, payloadTypeName, serializationTypeNameAnnotation); break; default: throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataVerboseJsonPropertyAndValueDeserializer_ReadPropertyValue)); } // If we have no expected type make sure the collection items are of the same kind and specify the same name. if (collectionValidator != null) { string payloadTypeNameFromResult = ODataVerboseJsonReaderUtils.GetPayloadTypeName(result); Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference."); collectionValidator.ValidateCollectionItem(payloadTypeNameFromResult, targetTypeKind); } } this.JsonReader.AssertNotBuffering(); return(result); }
/// <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> /// Reads the primitive, complex or collection value. /// </summary> /// <param name="expectedTypeReference">The expected type reference of the value.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param> /// <param name="validateNullValue">true to validate a null value; otherwise false.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The value read (null, primitive CLR value, ODataComplexValue or ODataCollectionValue).</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The XML element containing the value to read (also the attributes will be read from it) /// Post-Condition: XmlNodeType.EndElement - The end tag of the element. /// XmlNodeType.Element - The empty element node. /// </remarks> private object ReadNonEntityValueImplementation( IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent) { this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert( expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(), "Only primitive, complex or collection types can be read by this method."); Debug.Assert( expectedTypeReference == null || collectionValidator == null, "If an expected value type reference is specified, no collection validator must be provided."); this.XmlReader.AssertNotBuffering(); // Read the attributes looking for m:type and m:null string payloadTypeName; bool isNull; this.ReadNonEntityValueAttributes(out payloadTypeName, out isNull); object result; if (isNull) { result = this.ReadNullValue(expectedTypeReference, validateNullValue); } else { // If we could derive the item type name from the collection's type name and no type name was specified in the payload // fill it in now. EdmTypeKind payloadTypeKind; bool derivedItemTypeNameFromCollectionTypeName = false; if (collectionValidator != null && payloadTypeName == null) { payloadTypeName = collectionValidator.ItemTypeNameFromCollection; payloadTypeKind = collectionValidator.ItemTypeKindFromCollection; derivedItemTypeNameFromCollectionTypeName = payloadTypeKind != EdmTypeKind.None; } // Resolve the payload type name and compute the target type kind and target type reference. SerializationTypeNameAnnotation serializationTypeNameAnnotation; EdmTypeKind targetTypeKind; IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind.None, /*defaultPrimitivePayloadType*/ edmStringType, expectedTypeReference, payloadTypeName, this.Model, this.MessageReaderSettings, this.Version, this.GetNonEntityValueKind, out targetTypeKind, out serializationTypeNameAnnotation); if (derivedItemTypeNameFromCollectionTypeName) { Debug.Assert( serializationTypeNameAnnotation == null, "If we derived the item type name from the collection type name we must not have created a serialization type name annotation."); serializationTypeNameAnnotation = new SerializationTypeNameAnnotation { TypeName = null }; } // If we have no expected type make sure the collection items are of the same kind and specify the same name. if (collectionValidator != null) { Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference."); collectionValidator.ValidateCollectionItem(payloadTypeName, targetTypeKind); } switch (targetTypeKind) { case EdmTypeKind.Primitive: Debug.Assert(targetTypeReference != null && targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type."); result = this.ReadPrimitiveValue(targetTypeReference.AsPrimitive()); break; case EdmTypeKind.Complex: Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type."); result = this.ReadComplexValue( targetTypeReference == null ? null : targetTypeReference.AsComplex(), payloadTypeName, serializationTypeNameAnnotation, duplicatePropertyNamesChecker, epmPresent); break; case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference); result = this.ReadCollectionValue( collectionTypeReference, payloadTypeName, serializationTypeNameAnnotation); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue)); } } this.AssertXmlCondition(true, XmlNodeType.EndElement); this.XmlReader.AssertNotBuffering(); return(result); }
/// <summary> /// Validates that the specified <paramref name="expectedValueTypeReference"/> allows null values. /// </summary> /// <param name="expectedValueTypeReference">The expected type for the value, or null if no such type is available.</param> /// <param name="validateNullValue">true to validate the null value; otherwise false.</param> /// <param name="model">The model to use to get the OData-Version.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param> /// <param name="isDynamicProperty">Indicates whether the property is dynamic or unknown.</param> private static void ValidateNullValueAllowed(IEdmTypeReference expectedValueTypeReference, bool validateNullValue, IEdmModel model, string propertyName, bool? isDynamicProperty) { Debug.Assert(model != null, "For null validation, model is required."); if (validateNullValue && expectedValueTypeReference != null) { Debug.Assert( expectedValueTypeReference.IsODataPrimitiveTypeKind() || expectedValueTypeReference.IsODataTypeDefinitionTypeKind() || expectedValueTypeReference.IsODataEnumTypeKind() || expectedValueTypeReference.IsODataComplexTypeKind() || expectedValueTypeReference.IsNonEntityCollectionType(), "Only primitive, type definition, Enum, complex and collection types are supported by this method."); if (expectedValueTypeReference.IsODataPrimitiveTypeKind()) { // COMPAT 55: WCF DS allows null values for non-nullable properties // For now ODataLib will always fail on null value when it is to be reported for a non-nullable property // We should add a knob since WCF DS might need the different behavior. if (!expectedValueTypeReference.IsNullable) { ThrowNullValueForNonNullableTypeException(expectedValueTypeReference, propertyName); } } else if (expectedValueTypeReference.IsODataEnumTypeKind()) { if (!expectedValueTypeReference.IsNullable) { ThrowNullValueForNonNullableTypeException(expectedValueTypeReference, propertyName); } } else if (expectedValueTypeReference.IsNonEntityCollectionType()) { if (isDynamicProperty != true) { ThrowNullValueForNonNullableTypeException(expectedValueTypeReference, propertyName); } } else if (expectedValueTypeReference.IsODataComplexTypeKind()) { if (ValidationUtils.ShouldValidateComplexPropertyNullValue(model)) { IEdmComplexTypeReference complexTypeReference = expectedValueTypeReference.AsComplex(); if (!complexTypeReference.IsNullable) { ThrowNullValueForNonNullableTypeException(expectedValueTypeReference, propertyName); } } } } }