/// <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())); } } } }
public void CreateResource_CreateDeltaWith_OpenComplexType() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType <SimpleOpenAddress>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); ODataDeserializerContext readContext = new ODataDeserializerContext { Model = model, ResourceType = typeof(Delta <SimpleOpenAddress>) }; var structuralProperties = addressTypeReference.StructuralProperties().Select(p => p.Name); // Act Delta <SimpleOpenAddress> resource = ODataComplexTypeDeserializer.CreateResource(addressTypeReference, readContext) as Delta <SimpleOpenAddress>; // Assert Assert.NotNull(resource); Assert.Equal(structuralProperties, resource.GetUnchangedPropertyNames()); }
public ODataComplexTypeSerializerTests() { _model = SerializationTestsHelpers.SimpleCustomerOrderModel(); _address = new Address() { Street = "One Microsoft Way", City = "Redmond", State = "Washington", Country = "United States", ZipCode = "98052" }; _addressType = _model.FindDeclaredType("Default.Address") as IEdmComplexType; _model.SetAnnotationValue(_addressType, new ClrTypeAnnotation(typeof(Address))); _addressTypeRef = _addressType.ToEdmTypeReference(isNullable: false).AsComplex(); var cnAddressType = _model.FindDeclaredType("Default.CnAddress") as IEdmComplexType; _model.SetAnnotationValue(cnAddressType, new ClrTypeAnnotation(typeof(CnAddress))); var usAddressType = _model.FindDeclaredType("Default.UsAddress") as IEdmComplexType; _model.SetAnnotationValue(usAddressType, new ClrTypeAnnotation(typeof(UsAddress))); _locationType = _model.FindDeclaredType("Default.Location") as IEdmComplexType; _model.SetAnnotationValue(_locationType, new ClrTypeAnnotation(typeof(Location))); _locationTypeRef = _locationType.ToEdmTypeReference(isNullable: false).AsComplex(); ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); _serializer = new ODataComplexTypeSerializer(serializerProvider); TimeZoneInfoHelper.TimeZone = null; }
public static IEdmComplexTypeReference AsComplex(this IEdmTypeReference type) { EdmUtil.CheckArgumentNull <IEdmTypeReference>(type, "type"); IEdmComplexTypeReference edmComplexTypeReference = type as IEdmComplexTypeReference; if (edmComplexTypeReference == null) { IEdmType definition = type.Definition; if (definition.TypeKind != EdmTypeKind.Complex) { string str = type.FullName(); List <EdmError> edmErrors = new List <EdmError>(type.Errors()); if (edmErrors.Count == 0) { edmErrors.AddRange(EdmTypeSemantics.ConversionError(type.Location(), str, "Complex")); } return(new BadComplexTypeReference(str, type.IsNullable, edmErrors)); } else { return(new EdmComplexTypeReference((IEdmComplexType)definition, type.IsNullable)); } } else { return(edmComplexTypeReference); } }
public void EnumValueDeserializerTest(Color color) { // Arrange IEdmModel model = GetEdmModel(); var deserializer = new ODataResourceDeserializer(_deserializerProvider); ODataResource resourceValue = new ODataResource { Properties = new[] { new ODataProperty { Name = "RequiredColor", Value = new ODataEnumValue(color.ToString()) } }, TypeName = "Microsoft.AspNet.OData.Test.EnumComplexWithRequiredEnum" }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithRequiredEnum)).AsComplex(); // Act var enumComplexWithRequiredEnum = deserializer.ReadResource(new ODataResourceWrapper(resourceValue), enumComplexTypeReference, readContext) as EnumComplexWithRequiredEnum; // Assert Assert.NotNull(enumComplexWithRequiredEnum); Assert.Equal(color, enumComplexWithRequiredEnum.RequiredColor); }
public void NullEnumValueDeserializerTest() { // Arrange var deserializerProvider = new Mock <ODataDeserializerProvider>().Object; var deserializer = new ODataResourceDeserializer(deserializerProvider); ODataResource resourceValue = new ODataResource { Properties = new[] { new ODataProperty { Name = "NullableColor", Value = null } }, TypeName = "Microsoft.AspNet.OData.Test.EnumComplexWithNullableEnum" }; IEdmModel model = GetEdmModel(); ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithNullableEnum)).AsComplex(); // Act var enumComplexWithNullableEnum = deserializer.ReadResource(new ODataResourceWrapper(resourceValue), enumComplexTypeReference, readContext) as EnumComplexWithNullableEnum; // Assert Assert.NotNull(enumComplexWithNullableEnum); Assert.Null(enumComplexWithNullableEnum.NullableColor); }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return(complexResource); }
public void EnumValueDeserializerTest(Color color) { // Arrange var deserializerProvider = new Mock <ODataDeserializerProvider>().Object; var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "RequiredColor", Value = color } }, TypeName = "System.Web.OData.EnumComplexWithRequiredEnum" }; IEdmModel model = GetEdmModel(); ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithRequiredEnum)).AsComplex(); // Act var enumComplexWithRequiredEnum = deserializer.ReadComplexValue(complexValue, enumComplexTypeReference, readContext) as EnumComplexWithRequiredEnum; // Assert Assert.NotNull(enumComplexWithRequiredEnum); Assert.Equal(color, enumComplexWithRequiredEnum.RequiredColor); }
private ODataComplexValue ReadComplexValue(IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.IncreaseRecursionDepth(); ODataComplexValue value2 = new ODataComplexValue(); IEdmComplexType type = (complexTypeReference == null) ? null : ((IEdmComplexType)complexTypeReference.Definition); value2.TypeName = (type == null) ? payloadTypeName : type.ODataFullName(); if (serializationTypeNameAnnotation != null) { value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } base.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List <ODataProperty> properties = new List <ODataProperty>(); this.ReadPropertiesImplementation(type, properties, duplicatePropertyNamesChecker, epmPresent); value2.Properties = new ReadOnlyEnumerable <ODataProperty>(properties); this.DecreaseRecursionDepth(); return(value2); }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return complexResource; }
internal void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator) { this.IncreaseRecursionDepth(); base.JsonWriter.StartObjectScope(); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } IEdmComplexTypeReference type = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)) { typeName = null; } SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } if (typeName != null) { base.JsonWriter.WriteName("__metadata"); base.JsonWriter.StartObjectScope(); base.JsonWriter.WriteName("type"); base.JsonWriter.WriteValue(typeName); base.JsonWriter.EndObjectScope(); } this.WriteProperties((type == null) ? null : type.ComplexDefinition(), complexValue.Properties, true, duplicatePropertyNamesChecker, null); base.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
public void UndefinedEnumValueDeserializerTest() { // Arrange var deserializer = new ODataResourceDeserializer(_deserializerProvider); ODataResource resourceValue = new ODataResource { Properties = new[] { new ODataProperty { Name = "RequiredColor", Value = new ODataEnumValue("123") } }, TypeName = "System.Web.OData.EnumComplexWithRequiredEnum" }; IEdmModel model = GetEdmModel(); ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithRequiredEnum)).AsComplex(); // Act var enumComplexWithRequiredEnum = deserializer.ReadResource(new ODataResourceWrapper(resourceValue), enumComplexTypeReference, readContext) as EnumComplexWithRequiredEnum; // Assert Assert.NotNull(enumComplexWithRequiredEnum); Assert.Equal((Color)123, enumComplexWithRequiredEnum.RequiredColor); }
/// <summary> /// If this reference is of a complex type, this will return a valid complex type reference to the type definition. Otherwise, it will return a bad complex type reference. /// </summary> /// <param name="type">Reference to the calling object.</param> /// <returns>A valid complex type reference if the definition of the reference is of a complex type. Otherwise a bad complex type reference.</returns> public static IEdmComplexTypeReference AsComplex(this IEdmTypeReference type) { EdmUtil.CheckArgumentNull(type, "type"); IEdmComplexTypeReference reference = type as IEdmComplexTypeReference; if (reference != null) { return(reference); } IEdmType typeDefinition = type.Definition; if (typeDefinition.TypeKind == EdmTypeKind.Complex) { return(new EdmComplexTypeReference((IEdmComplexType)typeDefinition, type.IsNullable)); } string typeFullName = type.FullName(); List <EdmError> errors = new List <EdmError>(type.Errors()); if (errors.Count == 0) { errors.AddRange(ConversionError(type.Location(), typeFullName, EdmConstants.Type_Complex)); } return(new BadComplexTypeReference(typeFullName, type.IsNullable, errors)); }
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)); }
/// <summary> /// Initializes a new instance of the <see cref="NullEdmComplexObject"/> class. /// </summary> /// <param name="edmType">The EDM type of this object.</param> public NullEdmComplexObject(IEdmComplexTypeReference edmType) { if (edmType == null) { throw Error.ArgumentNull("edmType"); } _edmType = edmType; }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return(null); } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List <ODataProperty> propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext)); } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List <ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return null; } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext)); } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List<ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
/// <summary> /// Create a CollectionPropertyCastNode with the given source node and the given target type. /// </summary> /// <param name="source">Parent <see cref="CollectionPropertyAccessNode"/> that is being cast.</param> /// <param name="complexType">Type to cast to.</param> /// <exception cref="System.ArgumentNullException">Throws if the input source or complexType are null.</exception> public CollectionPropertyCastNode(CollectionPropertyAccessNode source, IEdmComplexType complexType) { ExceptionUtils.CheckArgumentNotNull(source, "source"); ExceptionUtils.CheckArgumentNotNull(complexType, "complexType"); this.source = source; this.edmTypeReference = new EdmComplexTypeReference(complexType, false); // creating a new collection type here because the type in the request is just the item type, there is no user-provided collection type. this.collectionTypeReference = EdmCoreModel.GetCollection(this.edmTypeReference); }
/// <summary> /// Constructs a new <see cref="CollectionComplexNode"/>. /// </summary> /// <param name="navigationSource">The navigation source containing the property.</param> /// <param name="property">The EDM property which is to be accessed.</param> /// <exception cref="System.ArgumentNullException">Throws if the input source or property is null.</exception> /// <exception cref="ArgumentException">Throws if the input property is not a collection of structural properties</exception> private CollectionComplexNode(IEdmNavigationSource navigationSource, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(property, "property"); if (property.PropertyKind != EdmPropertyKind.Structural) { throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessShouldBeNonEntityProperty(property.Name)); } this.property = property; this.collectionTypeReference = property.Type.AsCollection(); this.itemType = this.collectionTypeReference.ElementType().AsComplex(); this.navigationSource = navigationSource; }
/// <summary> /// Writes out the value of a complex property. /// </summary> /// <param name="complexValue">The complex value to write.</param> /// <param name="propertyTypeReference">The metadata type for the complex value.</param> /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param> /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between /// this complex value and the top-level payload, not including this one.</remarks> internal void WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire complex instance this.JsonWriter.StartObjectScope(); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } // resolve the type name to the type; if no type name is specified we will use the type inferred from metadata IEdmComplexTypeReference complexValueTypeReference = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, complexValue, isOpenPropertyType).AsComplexOrNull(); string collectionItemTypeName; typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexValueTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); // Write the "__metadata" : { "type": "typename" } // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely if (typeName != null) { ODataJsonWriterUtils.WriteMetadataWithTypeName(this.JsonWriter, typeName); } // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties. this.WriteProperties( complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(), complexValue.Properties, true /* isComplexValue */, duplicatePropertyNamesChecker, null /*projectedProperties */); // End the object scope which represents the complex instance this.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
/// <summary> /// Constructs a <see cref="SingleComplexNode"/>. /// </summary> /// <param name="navigationSource">The navigation source containing the property.</param> /// <param name="property">The EDM property which is to be accessed.</param> private SingleComplexNode(IEdmNavigationSource navigationSource, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(property, "property"); if (property.PropertyKind != EdmPropertyKind.Structural) { // TODO: update error message #644 throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessShouldBeNonEntityProperty(property.Name)); } this.property = property; this.navigationSource = navigationSource; this.typeReference = property.Type.AsComplex(); }
/// <summary> /// Creates and returns an OData complex type value using the specified object graph, tpye, and context. /// </summary> /// <param name="graph">The object graph to create a complex value for.</param> /// <param name="complexType">The type of complex type.</param> /// <param name="writeContext">The current <see cref="ODataSerializerContext">serializer context</see>.</param> /// <returns>The created <see cref="ODataComplexValue">complex value</see>.</returns> public override ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { var complexValue = base.CreateODataComplexValue(graph, complexType, writeContext); var context = new ODataSerializationFeatureContext(complexType, writeContext, ComplexTypeSerializer) { Instance = graph }; foreach (var feature in SerializationFeatures) { feature.Apply(complexValue, context); } return(complexValue); }
public ODataResourceDeserializerTests() { _edmModel = EdmTestHelpers.GetModel(); IEdmEntitySet entitySet = _edmModel.EntityContainer.FindEntitySet("Products"); _readContext = new ODataDeserializerContext { Path = new ODataPath(new EntitySetSegment(entitySet)), Model = _edmModel, ResourceType = typeof(Product) }; _productEdmType = _edmModel.GetEdmTypeReference(typeof(Product)).AsEntity(); _supplierEdmType = _edmModel.GetEdmTypeReference(typeof(Supplier)).AsEntity(); _addressEdmType = _edmModel.GetEdmTypeReference(typeof(Address)).AsComplex(); _deserializerProvider = DependencyInjectionHelper.GetDefaultODataDeserializerProvider(); }
internal static IEdmValue CreateStructuredEdmValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType) { if (complexType != null) { object typeAnnotation = ReflectionUtils.CreateInstance( odataTypeAnnotationType, new Type[] { typeof(IEdmComplexTypeReference) }, complexType); complexValue.SetAnnotation(typeAnnotation); } return (IEdmValue)ReflectionUtils.CreateInstance( odataEdmStructuredValueType, new Type[] { typeof(ODataComplexValue) }, complexValue); }
/// <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 void ReadComplexValue_CanReadDerivedComplexValue() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType <Address>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressEdmType = model.GetEdmTypeReference(typeof(Address)).AsComplex(); DefaultODataDeserializerProvider deserializerProvider = new DefaultODataDeserializerProvider(); ODataComplexTypeDeserializer deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "Street", Value = "12" }, new ODataProperty { Name = "City", Value = "Redmond" }, new ODataProperty { Name = "UsProp", Value = "UsPropertyValue" } }, TypeName = typeof(UsAddress).FullName }; ODataDeserializerContext readContext = new ODataDeserializerContext { Model = model }; // Act object address = deserializer.ReadComplexValue(complexValue, addressEdmType, readContext); // Assert Assert.NotNull(address); UsAddress usAddress = Assert.IsType <UsAddress>(address); Assert.Equal(usAddress.Street, "12"); Assert.Equal(usAddress.City, "Redmond"); Assert.Null(usAddress.Country); Assert.Null(usAddress.State); Assert.Null(usAddress.ZipCode); Assert.Equal("UsPropertyValue", usAddress.UsProp); }
internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext, List <ODataProperty> propertyCollection) { PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(), writeContext.Model); if (dynamicPropertyInfo != null) { IDictionary <string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph) as IDictionary <string, object>; if (dynamicPropertyDictionary != null) { // build a HashSet to store the declared property names. // It is used to make sure the dynamic property name is different with the declared property name. HashSet <string> declaredPropertyNameSet = new HashSet <string>(propertyCollection.Select(a => a.Name)); foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertyDictionary) { if (dynamicProperty.Value == null) { continue; // skip the null object } Type valueType = dynamicProperty.Value.GetType(); IEdmTypeReference edmTypeReference = writeContext.Model.GetEdmTypeReference(valueType); ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, valueType.FullName, typeof(ODataComplexTypeSerializer).Name); } // try to make sure the dynamic property name is not used as declared property name. if (declaredPropertyNameSet.Contains(dynamicProperty.Key)) { throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName, dynamicProperty.Key, complexType.FullName()); } propertyCollection.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } } } }
/// <summary> /// Read a complex value from the reader. /// </summary> /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param> /// <param name="payloadTypeName">The name of the type specified in the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The value read from the payload.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the element to read the value for. /// XmlNodeType.Attribute - an attribute on the element to read the value for. /// Post-Condition: XmlNodeType.EndElement - the element has been read. /// /// Note that this method will not read null values, those should be handled by the caller already. /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition; // If we have a metadata type for the complex value, use that type name // otherwise use the type name from the payload (if there was any). complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName(); if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } // Move to the element (so that if we were on an attribute we can test the element for being empty) this.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List <ODataProperty> properties = new List <ODataProperty>(); this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker, epmPresent); complexValue.Properties = new ReadOnlyEnumerable <ODataProperty>(properties); this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values."); this.DecreaseRecursionDepth(); return(complexValue); }
public void ReadComplexValue_Throws_IfDuplicateDynamicPropertyNameFound() { // Arrange ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.ComplexType <SimpleOpenAddress>(); IEdmModel model = builder.GetEdmModel(); IEdmComplexTypeReference addressTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenAddress)).AsComplex(); var deserializerProvider = new Mock <ODataDeserializerProvider>().Object; var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { // declared properties new ODataProperty { Name = "Street", Value = "My Way #599" }, new ODataProperty { Name = "City", Value = "Redmond & Shanghai" }, // dynamic properties new ODataProperty { Name = "GuidProperty", Value = new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA") }, new ODataProperty { Name = "GuidProperty", Value = new DateTimeOffset(new DateTime(1992, 1, 1)) } }, TypeName = "ODataDemo.Address" }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model }; // Act & Assert Assert.Throws <InvalidOperationException>(() => deserializer.ReadComplexValue(complexValue, addressTypeReference, readContext), "Duplicate dynamic property name 'GuidProperty' found in open type 'System.Web.OData.SimpleOpenAddress'. " + "Each dynamic property name must be unique."); }
public void CreateODataComplexValue_WritesBaseAndDerivedProperties_ForDerivedComplexType() { // Arrange IEdmModel model = SerializationTestsHelpers.SimpleCustomerOrderModel(); IEdmComplexType addressType = model.FindDeclaredType("Default.CnAddress") as IEdmComplexType; Type cnAddress = typeof(CnAddress); model.SetAnnotationValue <ClrTypeAnnotation>(addressType, new ClrTypeAnnotation(cnAddress)); IEdmComplexTypeReference addressTypeRef = addressType.ToEdmTypeReference(isNullable: false).AsComplex(); ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider(); ODataComplexTypeSerializer serializer = new ODataComplexTypeSerializer(serializerProvider); ODataSerializerContext context = new ODataSerializerContext { Model = model }; Address address = new CnAddress() { Street = "One Microsoft Way", City = "Redmond", State = "Washington", Country = "United States", ZipCode = "98052", CnProp = new Guid("F83FB4CC-84BD-403B-B411-79926800F9A5") }; // Act var odataValue = serializer.CreateODataComplexValue(address, addressTypeRef, context); // Assert ODataComplexValue complexValue = Assert.IsType <ODataComplexValue>(odataValue); Assert.Equal(complexValue.TypeName, "Default.CnAddress"); Assert.Equal(6, complexValue.Properties.Count()); // Verify the derived property ODataProperty street = Assert.Single(complexValue.Properties.Where(p => p.Name == "CnProp")); Assert.Equal(new Guid("F83FB4CC-84BD-403B-B411-79926800F9A5"), street.Value); }
internal static object CreateResource(IEdmComplexTypeReference edmComplexType, ODataDeserializerContext readContext) { Contract.Assert(edmComplexType != null); if (readContext.IsUntyped) { return(new EdmComplexObject(edmComplexType)); } else { Type clrType = EdmLibHelpers.GetClrType(edmComplexType, readContext.Model); if (clrType == null) { throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, edmComplexType.FullName()); } return(Activator.CreateInstance(clrType)); } }
public void ComplexType_reference_extensions() { IEdmModel edmModel = this.GetEdmModel(); IEdmComplexType derivedComplexType = edmModel.SchemaElements.OfType <IEdmComplexType>().First(c => c.BaseType != null); IEdmComplexType baseComplexType = derivedComplexType.BaseComplexType(); Assert.IsNotNull(baseComplexType, "Base complex type should not be null!"); IEdmComplexTypeReference derivedComplexTypeRef = (IEdmComplexTypeReference)derivedComplexType.ToTypeReference(); Assert.AreEqual(baseComplexType, derivedComplexTypeRef.BaseComplexType(), "ComplexTypeReference.BaseComplexType()"); Assert.AreEqual(baseComplexType, derivedComplexTypeRef.BaseType(), "ComplexTypeReference.BaseType()"); Assert.AreEqual(derivedComplexType.IsAbstract, derivedComplexTypeRef.IsAbstract(), "StructuralTypeReference.IsAbstract()"); Assert.AreEqual(derivedComplexType.IsOpen, derivedComplexTypeRef.IsOpen(), "StructuralTypeReference.IsOpen()"); Assert.AreEqual(derivedComplexType.DeclaredStructuralProperties().Count(), derivedComplexTypeRef.DeclaredStructuralProperties().Count(), "StructuralTypeReference.DeclaredStructuralProperties()"); Assert.AreEqual(derivedComplexType.StructuralProperties().Count(), derivedComplexTypeRef.StructuralProperties().Count(), "StructuralTypeReference.StructuralProperties()"); }
/// <summary> /// Constructs a <see cref="SingleValuePropertyAccessNode"/>. /// </summary> /// <param name="source">The value containing this property.</param> /// <param name="property">The EDM property which is to be accessed.</param> /// <exception cref="System.ArgumentNullException">Throws if input source or property is null.</exception> /// <exception cref="ArgumentException">Throws if input property is not structural, or is a collection.</exception> public AggregatedCollectionPropertyNode(CollectionNavigationNode source, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(source, "source"); ExceptionUtils.CheckArgumentNotNull(property, "property"); if (property.PropertyKind != EdmPropertyKind.Structural) { throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessShouldBeNonEntityProperty(property.Name)); } if (property.Type.IsCollection()) { throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessTypeShouldNotBeCollection(property.Name)); } this.source = source; this.property = property; this.typeReference = property.Type.AsComplex(); this.navigationSource = source.NavigationSource; }
private object ReadComplexPropertyValue(EntityPropertyMappingInfo epmInfo, ODataComplexValue complexValue, EpmValueCache epmValueCache, int sourceSegmentIndex, IEdmComplexTypeReference complexType) { return this.ReadPropertyValue(epmInfo, EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false), sourceSegmentIndex, complexType, epmValueCache); }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object /// (or the second property if the first one was odata.type).</param> /// <param name="insideComplexValue">true if we are reading a complex value and the reader is already positioned inside the complex value; otherwise false.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - this is always initialized as necessary, do not clear.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.Property - the first property of the complex value object, or the second one if the first one was odata.type. /// JsonNodeType.EndObject - the end object of the complex value object. /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValue( bool insideJsonObjectValue, bool insideComplexValue, string propertyName, IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { if (!insideJsonObjectValue && !insideComplexValue) { if (this.JsonReader.NodeType != JsonNodeType.StartObject) { string typeName = complexValueTypeReference != null ? complexValueTypeReference.FullName() : payloadTypeName; throw new ODataException( string.Format(CultureInfo.InvariantCulture, "The property with name '{0}' was found with a value node of type '{1}'; however, a complex value of type '{2}' was expected.", propertyName, this.JsonReader.NodeType, typeName)); } this.JsonReader.Read(); } return this.ReadComplexValue(complexValueTypeReference, payloadTypeName, serializationTypeNameAnnotation, duplicatePropertyNamesChecker); }
/// <summary> /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class. /// </summary> /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param> /// <param name="assembliesResolver">The assemblies resolve to use for type resolution</param> public EdmComplexObject(IEdmComplexTypeReference edmType, AssembliesResolver assembliesResolver) : this(edmType.ComplexDefinition(), assembliesResolver, edmType.IsNullable) { }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName) { // received a derived complex type in a base type deserializer. IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType; if (actualType == null) { throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName)); } if (actualType.IsAbstract) { string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType, complexValue.TypeName); throw new ODataException(message); } IEdmTypeReference actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false); ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType); if (deserializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext); EdmStructuredObject structuredObject = resource as EdmStructuredObject; if (structuredObject != null) { structuredObject.ExpectedEdmType = complexType.ComplexDefinition(); } return resource; } else { object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return complexResource; } }
private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataComplexValue value2 = new ODataComplexValue { TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> sourceList = new List<ODataProperty>(); bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } flag = true; base.JsonReader.SkipValue(); } else if (!ValidationUtils.IsValidPropertyName(strB)) { base.JsonReader.SkipValue(); } else { ODataProperty property = new ODataProperty { Name = strB }; IEdmProperty property2 = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { base.JsonReader.SkipValue(); continue; } ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2); object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default); if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null)) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = obj2; sourceList.Add(property); } } } base.JsonReader.ReadEndObject(); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(sourceList); this.DecreaseRecursionDepth(); return value2; }
/// <summary> /// Reads a property value starting on a complex value. /// </summary> /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param> /// <param name="complexValue">The complex value to start with.</param> /// <param name="epmValueCache">The EPM value cache to use.</param> /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param> /// <param name="complexType">The type of the complex value.</param> /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns> private object ReadComplexPropertyValue( EntityPropertyMappingInfo epmInfo, ODataComplexValue complexValue, EpmValueCache epmValueCache, int sourceSegmentIndex, IEdmComplexTypeReference complexType) { Debug.Assert(epmInfo != null, "epmInfo != null"); Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now."); Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(sourceSegmentIndex >= 0, "sourceSegmentIndex >= 0"); Debug.Assert(complexType != null, "complexType != null"); Debug.Assert(complexValue != null, "complexValue != null"); return this.ReadPropertyValue( epmInfo, EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false), sourceSegmentIndex, complexType, epmValueCache); }
/// <summary> /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class. /// </summary> /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param> public EdmComplexObject(IEdmComplexTypeReference edmType) : this(edmType.ComplexDefinition(), edmType.IsNullable) { }
internal static object CreateResource(IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexType == null) { throw Error.ArgumentNull("complexType"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (readContext.IsUntyped) { return new EdmComplexObject(complexType); } else { Type clrType = EdmLibHelpers.GetClrType(complexType, readContext.Model); if (clrType == null) { throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, complexType.FullName()); } if (readContext.IsDeltaOfT) { Type elementType = readContext.ResourceType.GetGenericArguments()[0]; if (elementType != clrType) { // Just create the object for inline complex type return Activator.CreateInstance(clrType); } IEnumerable<string> structuralProperties = complexType.StructuralProperties() .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model)); if (complexType.IsOpen()) { PropertyInfo dynamicDictionaryPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary( complexType.StructuredDefinition(), model); return Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties, dynamicDictionaryPropertyInfo); } else { return Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties); } } else { return Activator.CreateInstance(clrType); } } }
internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext, List<ODataProperty> propertyCollection) { PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(), writeContext.Model); if (dynamicPropertyInfo != null) { IDictionary<string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph) as IDictionary<string, object>; if (dynamicPropertyDictionary != null) { // build a HashSet to store the declared property names. // It is used to make sure the dynamic property name is different with the declared property name. HashSet<string> declaredPropertyNameSet = new HashSet<string>(propertyCollection.Select(a => a.Name)); foreach (KeyValuePair<string, object> dynamicProperty in dynamicPropertyDictionary) { if (dynamicProperty.Value == null) { continue; // skip the null object } Type valueType = dynamicProperty.Value.GetType(); IEdmTypeReference edmTypeReference = writeContext.Model.GetEdmTypeReference(valueType); ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, valueType.FullName, typeof(ODataComplexTypeSerializer).Name); } // try to make sure the dynamic property name is not used as declared property name. if (declaredPropertyNameSet.Contains(dynamicProperty.Key)) { throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName, dynamicProperty.Key, complexType.FullName()); } propertyCollection.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } } } }
private ODataComplexValue ReadComplexValue(IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.IncreaseRecursionDepth(); ODataComplexValue value2 = new ODataComplexValue(); IEdmComplexType type = (complexTypeReference == null) ? null : ((IEdmComplexType) complexTypeReference.Definition); value2.TypeName = (type == null) ? payloadTypeName : type.ODataFullName(); if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } base.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); this.ReadPropertiesImplementation(type, properties, duplicatePropertyNamesChecker, epmPresent); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.DecreaseRecursionDepth(); return value2; }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value) /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValueImplementation( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.JsonReader.AssertNotBuffering(); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property. if (metadataPropertyFound) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } metadataPropertyFound = true; this.JsonReader.SkipValue(); } else { if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { this.JsonReader.SkipValue(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; properties.Add(property); } } } } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return complexValue; }
public ODataComplexTypeDeserializer(IEdmComplexTypeReference edmComplexType, ODataDeserializerProvider deserializerProvider) : base(edmComplexType, ODataPayloadKind.Property, deserializerProvider) { EdmComplexType = edmComplexType; }
/// <summary> /// Read a complex value from the reader. /// </summary> /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param> /// <param name="payloadTypeName">The name of the type specified in the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <returns>The value read from the payload.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the element to read the value for. /// XmlNodeType.Attribute - an attribute on the element to read the value for. /// Post-Condition: XmlNodeType.EndElement - the element has been read. /// /// Note that this method will not read null values, those should be handled by the caller already. /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition; // If we have a metadata type for the complex value, use that type name // otherwise use the type name from the payload (if there was any). complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName(); if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } // Move to the element (so that if we were on an attribute we can test the element for being empty) this.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } ReadOnlyEnumerable<ODataProperty> properties = new ReadOnlyEnumerable<ODataProperty>(); this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker); complexValue.Properties = properties; this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values."); this.DecreaseRecursionDepth(); return complexValue; }
/// <summary> /// Initializes a new instance of the <see cref="TypedEdmComplexObject"/> class. /// </summary> /// <param name="instance">The backing CLR instance.</param> /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param> public TypedEdmComplexObject(object instance, IEdmComplexTypeReference edmType) : base(instance, edmType) { }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - this is always initialized as necessary, do not clear.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.Property - the first property of the complex value object, or the second one if the first one was odata.type. /// JsonNodeType.EndObject - the end object of the complex value object. /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.FullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (complexValueTypeReference != null) { complexValue.SetAnnotation(new ODataTypeAnnotation(complexValueTypeReference)); } List<ODataProperty> properties = new List<ODataProperty>(); while (this.JsonReader.NodeType == JsonNodeType.Property) { this.ReadPropertyCustomAnnotationValue = this.ReadCustomInstanceAnnotationValue; this.ProcessProperty( duplicatePropertyNamesChecker, this.ReadTypePropertyAnnotationValue, (propertyParsingResult, propertyName) => { switch (propertyParsingResult) { case PropertyParsingResult.ODataInstanceAnnotation: if (string.CompareOrdinal(ODataAnnotationNames.ODataType, propertyName) == 0) { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexTypeAnnotationNotFirst); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName)); } case PropertyParsingResult.CustomInstanceAnnotation: ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName); Debug.Assert( !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName), "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(annotationName) -- otherwise we should have already skipped the custom annotation and won't see it here."); var customInstanceAnnotationValue = this.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, propertyName); complexValue.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, customInstanceAnnotationValue.ToODataValue())); break; case PropertyParsingResult.PropertyWithoutValue: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexValuePropertyAnnotationWithoutProperty(propertyName)); case PropertyParsingResult.PropertyWithValue: // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty && (this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray)) { this.JsonReader.SkipValue(); } else { // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable. // If the property has an annotation to ignore null values, we need to omit the property in requests. ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( ValidateDataPropertyTypeNameAnnotation(duplicatePropertyNamesChecker, propertyName), edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, /*isTopLevelPropertyValue*/ false, /*insideComplexValue*/ false, propertyName, edmProperty == null); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; var propertyAnnotations = duplicatePropertyNamesChecker.GetCustomPropertyAnnotations(propertyName); if (propertyAnnotations != null) { foreach (var annotation in propertyAnnotations) { if (annotation.Value != null) { // annotation.Value == null indicates that this annotation should be skipped. property.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Key, annotation.Value.ToODataValue())); } } } properties.Add(property); } } break; case PropertyParsingResult.EndOfObject: break; case PropertyParsingResult.MetadataReferenceProperty: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName)); } }); } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.DecreaseRecursionDepth(); return complexValue; }
internal static object CreateResource(IEdmComplexTypeReference edmComplexType, ODataDeserializerContext readContext) { Contract.Assert(edmComplexType != null); if (readContext.IsUntyped) { return new EdmComplexObject(edmComplexType); } else { Type clrType = EdmLibHelpers.GetClrType(edmComplexType, readContext.Model); if (clrType == null) { throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, edmComplexType.FullName()); } return Activator.CreateInstance(clrType); } }
public ODataComplexTypeSerializer(IEdmComplexTypeReference edmComplexType, ODataSerializerProvider serializerProvider) : base(edmComplexType, ODataPayloadKind.Property, serializerProvider) { _edmComplexType = edmComplexType; }
/// <summary> /// Creates a new instance of the type annotation for a complex value. /// </summary> /// <param name="complexType">The type of the complex value (required).</param> public ODataTypeAnnotation(IEdmComplexTypeReference complexType) { ExceptionUtils.CheckArgumentNotNull(complexType, "complexType"); this.type = complexType; }
protected override void ProcessComplexTypeReference(IEdmComplexTypeReference element) { this.CheckSchemaElementReference(element.ComplexDefinition()); }