public void ReadInline() { // Arrange var deserializerProvider = new Mock<ODataDeserializerProvider>(EdmTestHelpers.GetModel()).Object; var deserializer = new ODataComplexTypeDeserializer(_addressEdmType, deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "Street", Value = "12"}, new ODataProperty { Name = "City", Value = "Redmond"} }, TypeName = "ODataDemo.Address" }; // Act ODataEntityDeserializerTests.Address address = deserializer.ReadInline( complexValue, new ODataDeserializerReadContext()) as ODataEntityDeserializerTests.Address; // Assert Assert.NotNull(address); Assert.Equal(address.Street, "12"); Assert.Equal(address.City, "Redmond"); Assert.Null(address.Country); Assert.Null(address.State); Assert.Null(address.ZipCode); }
internal static void AddTypeNameAnnotationAsNeeded(ODataComplexValue value, ODataMetadataLevel metadataLevel) { // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties // null when values should not be serialized. The TypeName property is different and should always be // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not // to serialize the type name (a null value prevents serialization). // Note that this annotation should not be used for Atom or JSON verbose formats, as it will interfere with // the correct default behavior for those formats. Contract.Assert(value != null); // Only add an annotation if we want to override ODataLib's default type name serialization behavior. if (ShouldAddTypeNameAnnotation(metadataLevel)) { string typeName; // Provide the type name to serialize (or null to force it not to serialize). if (ShouldSuppressTypeNameSerialization(metadataLevel)) { typeName = null; } else { typeName = value.TypeName; } value.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation { TypeName = typeName }); } }
/// <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 static IEnumerable<ODataProperty> GetComplexValueProperties(EpmValueCache epmValueCache, ODataComplexValue complexValue, bool writingContent) { if (epmValueCache == null) { return complexValue.Properties; } return epmValueCache.GetComplexValueProperties(complexValue, writingContent); }
private IEnumerable<ODataProperty> GetComplexValueProperties(ODataComplexValue complexValue, bool writingContent) { object obj2; if ((this.epmValuesCache != null) && this.epmValuesCache.TryGetValue(complexValue, out obj2)) { return (IEnumerable<ODataProperty>) obj2; } return complexValue.Properties; }
public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation_InDefaultMetadataMode() { // Arrange ODataComplexValue value = new ODataComplexValue(); // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.Default); // Assert Assert.Null(value.GetAnnotation<SerializationTypeNameAnnotation>()); }
public override ODataProperty CreateProperty(object graph, string elementName, ODataSerializerContext writeContext) { if (String.IsNullOrWhiteSpace(elementName)) { throw Error.ArgumentNullOrEmpty("elementName"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null) { return new ODataProperty() { Name = elementName, Value = null }; } else { List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported("Type {0} is not a serializable type", propertyType.FullName()); } // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter. object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null); propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext)); } string typeName = _edmComplexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; // Required to support JSON light full metadata mode. value.SetAnnotation<SerializationTypeNameAnnotation>( new SerializationTypeNameAnnotation { TypeName = typeName }); return new ODataProperty() { Name = elementName, Value = value }; } }
private object ConvertComplexValue(ODataComplexValue complexValue, ref ResourceType complexResourceType) { if (complexResourceType == null) { complexResourceType = base.Service.Provider.TryResolveResourceType(complexValue.TypeName); } base.CheckAndIncrementObjectCount(); base.RecurseEnter(); object resource = base.Updatable.CreateResource(null, complexResourceType.FullName); foreach (ODataProperty property in complexValue.Properties) { this.ApplyProperty(property, complexResourceType, resource); } base.RecurseLeave(); return resource; }
public void AddTypeNameAnnotationAsNeeded_AddsAnnotation_InJsonLightMetadataMode() { // Arrange string expectedTypeName = "TypeName"; ODataComplexValue value = new ODataComplexValue { TypeName = expectedTypeName }; // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.FullMetadata); // Assert SerializationTypeNameAnnotation annotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); Assert.NotNull(annotation); // Guard Assert.Equal(expectedTypeName, annotation.TypeName); }
public void ReadInline_Calls_ReadComplexValue() { // Arrange ODataDeserializerProvider deserializerProvider = new DefaultODataDeserializerProvider(); Mock<ODataComplexTypeDeserializer> deserializer = new Mock<ODataComplexTypeDeserializer>(deserializerProvider); ODataComplexValue item = new ODataComplexValue(); ODataDeserializerContext readContext = new ODataDeserializerContext(); deserializer.CallBase = true; deserializer.Setup(d => d.ReadComplexValue(item, _addressEdmType, readContext)).Returns(42).Verifiable(); // Act object result = deserializer.Object.ReadInline(item, _addressEdmType, readContext); // Assert deserializer.Verify(); Assert.Equal(42, result); }
internal IEnumerable<ODataProperty> CacheComplexValueProperties(ODataComplexValue complexValue) { if (complexValue == null) { return null; } IEnumerable<ODataProperty> properties = complexValue.Properties; List<ODataProperty> list = null; if (properties != null) { list = new List<ODataProperty>(properties); } if (this.epmValuesCache == null) { this.epmValuesCache = new Dictionary<object, object>(ReferenceEqualityComparer<object>.Instance); } this.epmValuesCache.Add(complexValue, list); return list; }
public override ODataValue CreateODataValue(object graph, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null) { return new ODataNullValue(); } else { List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEntrySerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported("Type {0} is not a serializable type", propertyType.FullName()); } // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter. object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null); propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext)); } string typeName = _edmComplexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; } }
/// <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; }
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); } else { edmComplexType = propertyType.AsComplex(); } ODataEdmTypeDeserializer deserializer = deserializerProvider.GetEdmTypeDeserializer(edmComplexType); return deserializer.ReadInline(complexValue, propertyType, readContext); }
public void ReadComplexValue_CanReadComplexValue() { // Arrange var deserializerProvider = new Mock<ODataDeserializerProvider>().Object; var deserializer = new ODataComplexTypeDeserializer(deserializerProvider); ODataComplexValue complexValue = new ODataComplexValue { Properties = new[] { new ODataProperty { Name = "Street", Value = "12"}, new ODataProperty { Name = "City", Value = "Redmond"} }, TypeName = "ODataDemo.Address" }; ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = _edmModel }; // Act var address = deserializer.ReadComplexValue(complexValue, _addressEdmType, readContext) as ODataEntityDeserializerTests.Address; // Assert Assert.NotNull(address); Assert.Equal(address.Street, "12"); Assert.Equal(address.City, "Redmond"); Assert.Null(address.Country); Assert.Null(address.State); Assert.Null(address.ZipCode); }
public void WriteObject_Calls_CreateODataComplexValue() { // Arrange MemoryStream stream = new MemoryStream(); IODataResponseMessage message = new ODataMessageWrapper(stream); ODataMessageWriter messageWriter = new ODataMessageWriter(message); Mock<ODataComplexTypeSerializer> serializer = new Mock<ODataComplexTypeSerializer>(_serializer.ComplexType, new DefaultODataSerializerProvider()); ODataSerializerContext writeContext = new ODataSerializerContext { RootElementName = "ComplexPropertyName" }; object graph = new object(); ODataComplexValue complexValue = new ODataComplexValue { TypeName = "NS.Name", Properties = new[] { new ODataProperty { Name = "Property1", Value = 42 } } }; serializer.CallBase = true; serializer.Setup(s => s.CreateODataComplexValue(graph, writeContext)).Returns(complexValue).Verifiable(); // Act serializer.Object.WriteObject(graph, messageWriter, writeContext); // Assert serializer.Verify(); stream.Seek(0, SeekOrigin.Begin); XElement element = XElement.Load(stream); Assert.Equal("ComplexPropertyName", element.Name.LocalName); Assert.Equal("NS.Name", element.Attributes().Single(a => a.Name.LocalName == "type").Value); Assert.Equal(1, element.Descendants().Count()); Assert.Equal("42", element.Descendants().Single().Value); Assert.Equal("Property1", element.Descendants().Single().Name.LocalName); }
protected static void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue, bool ignoreMissingProperties, System.Data.Services.Client.ResponseInfo responseInfo) { object instance = null; if ((complexValue != null) && !complexValue.HasMaterializedValue()) { ClientTypeAnnotation actualType = null; if (WebUtil.IsWireTypeCollection(complexValue.TypeName)) { actualType = responseInfo.TypeResolver.ResolveEdmTypeName(propertyType, complexValue.TypeName); } else { ClientEdmModel model = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion); actualType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(propertyType)); } instance = Util.ActivatorCreateInstance(propertyType, new object[0]); MaterializeDataValues(actualType, complexValue.Properties, ignoreMissingProperties); ApplyDataValues(actualType, complexValue.Properties, ignoreMissingProperties, responseInfo, instance); complexValue.SetMaterializedValue(instance); } }
internal static void AddTypeNameAnnotationAsNeeded(ODataComplexValue value, ODataMetadataLevel metadataLevel) { Contract.Assert(value != null); if (ShouldAddTypeNameAnnotation(metadataLevel)) { string typeName; if (ShouldSuppressTypeNameSerialization(metadataLevel)) { typeName = null; } else { typeName = value.TypeName; } value.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation { TypeName = typeName }); } }
public void CreateODataValue_Calls_CreateODataComplexValue() { // Arrange var oDataComplexValue = new ODataComplexValue(); var complexObject = new object(); Mock<ODataComplexTypeSerializer> serializer = new Mock<ODataComplexTypeSerializer>(_serializer.ComplexType, new DefaultODataSerializerProvider()); serializer.CallBase = true; serializer .Setup(s => s.CreateODataComplexValue(complexObject, It.IsAny<ODataSerializerContext>())) .Returns(oDataComplexValue) .Verifiable(); // Act ODataValue value = serializer.Object.CreateODataValue(complexObject, new ODataSerializerContext()); // Assert serializer.Verify(); Assert.Same(oDataComplexValue, value); }
private void SetEpmValueForSegment( EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, List<ODataProperty> existingProperties, object propertyValue) { Debug.Assert(epmInfo != null, "epmInfo != null"); Debug.Assert(propertyValuePathIndex < epmInfo.PropertyValuePath.Length, "The propertyValuePathIndex is out of bounds."); Debug.Assert(existingProperties != null, "existingProperties != null"); string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName; // Do not set out-of-content values if the EPM is defined as KeepInContent=true. if (epmInfo.Attribute.KeepInContent) { return; } // Try to find the property in the existing properties // If the property value is atomic from point of view of EPM (non-streaming collection or primitive) then if it already exists // it must have been in-content, and thus we leave it as is (note that two EPMs can't map to the same property, we verify that upfront). // If the property value is non-atomic, then it is a complex value, we might want to merge the new value comming from EPM with it. ODataProperty existingProperty = existingProperties.FirstOrDefault(p => string.CompareOrdinal(p.Name, propertyName) == 0); ODataComplexValue existingComplexValue = null; if (existingProperty != null) { // In case the property exists and it's a complex value we will try to merge. // Note that if the property is supposed to be complex, but it already has a null value, then the null wins. // Since in-content null complex value wins over any EPM complex value. existingComplexValue = existingProperty.Value as ODataComplexValue; if (existingComplexValue == null) { return; } } IEdmProperty propertyMetadata = segmentStructuralTypeReference.FindProperty(propertyName); Debug.Assert(propertyMetadata != null || segmentStructuralTypeReference.IsOpen(), "We should have verified that if the property is not declared the type must be open."); if (propertyMetadata == null && propertyValuePathIndex != epmInfo.PropertyValuePath.Length - 1) { throw new ODataException(o.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath)); } // Open properties in EPM are by default of type Edm.String - there's no way to specify a typename in EPM // consumer is free to do the conversion later on if it needs to. // Note that this effectively means that ODataMessageReaderSettings.DisablePrimitiveTypeConversion is as if it's turned on for open EPM properties. IEdmTypeReference propertyType; if (propertyMetadata == null || (this.MessageReaderSettings.DisablePrimitiveTypeConversion && propertyMetadata.Type.IsODataPrimitiveTypeKind())) { propertyType = EdmCoreModel.Instance.GetString(/*nullable*/true); } else { propertyType = propertyMetadata.Type; } // NOTE: WCF DS Server only applies the values when // - It's an open property // - It's not a key property // - It's a key property and it's a POST operation // ODataLib here will always set the property though. switch (propertyType.TypeKind()) { case EdmTypeKind.Primitive: { if (propertyType.IsStream()) { throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty)); } object primitiveValue; if (propertyValue == null) { ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, propertyType, this.atomInputContext.MessageReaderSettings, /*validateNullValue*/ true, this.atomInputContext.Version); primitiveValue = null; } else { // Convert the value to the desired target type primitiveValue = AtomValueUtils.ConvertStringToPrimitive((string)propertyValue, propertyType.AsPrimitive()); } this.AddEpmPropertyValue(existingProperties, propertyName, primitiveValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); } break; case EdmTypeKind.Complex: // Note: Unlike WCF DS we don't have a preexisting instance to override (since complex values are atomic, so we should not updated them) // In our case the complex value either doesn't exist yet on the entry being reported (easy, create it) // or it exists, but then it was created during reading of previous normal or EPM properties for this entry. It never exists before // we ever get to see the entity. So in our case we will never recreate the complex value, we always start with new one // and update it with new properties as they come. (Next time we will start over with a new complex value.) Debug.Assert( existingComplexValue == null || (existingProperty != null && existingProperty.Value == existingComplexValue), "If we have existing complex value, we must have an existing property as well."); Debug.Assert( epmInfo.PropertyValuePath.Length > propertyValuePathIndex + 1, "Complex value can not be a leaf segment in the source property path. We should have failed constructing the EPM trees for it."); if (existingComplexValue == null) { Debug.Assert(existingProperty == null, "If we don't have an existing complex value, then we must not have an existing property at all."); // Create a new complex value and set its type name to the type name of the property type (in case of EPM we never have type name from the payload) existingComplexValue = new ODataComplexValue { TypeName = propertyType.ODataFullName(), Properties = new ReadOnlyEnumerable<ODataProperty>() }; this.AddEpmPropertyValue(existingProperties, propertyName, existingComplexValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); } // Get the properties list of the complex value and recursively set the next EPM segment value to it. // Note that on inner complex value we don't need to check for duplicate properties // because EPM will never add a property which already exists (see the start of this method). IEdmComplexTypeReference complexPropertyTypeReference = propertyType.AsComplex(); Debug.Assert(complexPropertyTypeReference != null, "complexPropertyTypeReference != null"); this.SetEpmValueForSegment( epmInfo, propertyValuePathIndex + 1, complexPropertyTypeReference, ReaderUtils.GetPropertiesList(existingComplexValue.Properties), propertyValue); break; case EdmTypeKind.Collection: Debug.Assert(propertyType.IsNonEntityODataCollectionTypeKind(), "Collection types in EPM must be atomic."); // In this case the property value is the internal list of items. // Create a new collection value and set the list as the list of items on it. ODataCollectionValue collectionValue = new ODataCollectionValue { TypeName = propertyType.ODataFullName(), Items = new ReadOnlyEnumerable((List<object>)propertyValue) }; this.AddEpmPropertyValue(existingProperties, propertyName, collectionValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind)); } }
private static IEnumerable<ODataProperty> ConvertProperties(JObject entry, IEnumerable<string> fieldsToIgnore) { var properties = new List<ODataProperty>(); foreach (var property in entry.Properties()) { if (fieldsToIgnore.Contains(property.Name)) { continue; } object odataPropertyValue; var propertyValue = property.Value; if (propertyValue.Type == JTokenType.Object) { // TODO: recurse var complex = new ODataComplexValue(); complex.Properties = ConvertProperties((JObject) propertyValue, fieldsToIgnore); odataPropertyValue = complex; } else { odataPropertyValue = ((JValue) propertyValue).Value; } properties.Add(new ODataProperty {Name = property.Name, Value = odataPropertyValue}); } return properties; }
/// <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); 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)); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
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> /// 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(); // Write the "__metadata" : { "type": "typename" } // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely 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 = WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (typeName != null && collectionValidator != null) { string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection; if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0) { typeName = null; } } SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } if (typeName != null) { // Write the __metadata object this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // "type": "typename" this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); // End the __metadata this.JsonWriter.EndObjectScope(); } // 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(); }
private void SetEpmValueForSegment(EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, List<ODataProperty> existingProperties, object propertyValue) { string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName; if (!epmInfo.Attribute.KeepInContent) { IEdmTypeReference type; ODataProperty property = existingProperties.FirstOrDefault<ODataProperty>(p => string.CompareOrdinal(p.Name, propertyName) == 0); ODataComplexValue value2 = null; if (property != null) { value2 = property.Value as ODataComplexValue; if (value2 == null) { return; } } IEdmProperty property2 = segmentStructuralTypeReference.FindProperty(propertyName); if ((property2 == null) && (propertyValuePathIndex != (epmInfo.PropertyValuePath.Length - 1))) { throw new ODataException(Microsoft.Data.OData.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath)); } if ((property2 == null) || (this.MessageReaderSettings.DisablePrimitiveTypeConversion && property2.Type.IsODataPrimitiveTypeKind())) { type = EdmCoreModel.Instance.GetString(true); } else { type = property2.Type; } switch (type.TypeKind()) { case EdmTypeKind.Primitive: object obj2; if (type.IsStream()) { throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty)); } if (propertyValue == null) { ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, type, this.atomInputContext.MessageReaderSettings, true, this.atomInputContext.Version); obj2 = null; } else { obj2 = AtomValueUtils.ConvertStringToPrimitive((string) propertyValue, type.AsPrimitive()); } this.AddEpmPropertyValue(existingProperties, propertyName, obj2, segmentStructuralTypeReference.IsODataEntityTypeKind()); return; case EdmTypeKind.Complex: { if (value2 == null) { value2 = new ODataComplexValue { TypeName = type.ODataFullName(), Properties = new ReadOnlyEnumerable<ODataProperty>() }; this.AddEpmPropertyValue(existingProperties, propertyName, value2, segmentStructuralTypeReference.IsODataEntityTypeKind()); } IEdmComplexTypeReference reference2 = type.AsComplex(); this.SetEpmValueForSegment(epmInfo, propertyValuePathIndex + 1, reference2, ReaderUtils.GetPropertiesList(value2.Properties), propertyValue); return; } case EdmTypeKind.Collection: { ODataCollectionValue value4 = new ODataCollectionValue { TypeName = type.ODataFullName(), Items = new ReadOnlyEnumerable((List<object>) propertyValue) }; this.AddEpmPropertyValue(existingProperties, propertyName, value4, segmentStructuralTypeReference.IsODataEntityTypeKind()); return; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind)); } }
/// <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); }
private ODataComplexValue CreateODataComplexValue(Type complexType, object value, string propertyName, bool isCollectionItem, List<object> visitedComplexTypeObjects) { ClientTypeAnnotation clientTypeAnnotation = ClientEdmModel.GetModel(this.requestInfo.MaxProtocolVersion).GetClientTypeAnnotation(complexType); if (visitedComplexTypeObjects == null) { visitedComplexTypeObjects = new List<object>(); } else if (visitedComplexTypeObjects.Contains(value)) { if (propertyName != null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName)); } throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(clientTypeAnnotation.ElementTypeName)); } if (value == null) { return null; } visitedComplexTypeObjects.Add(value); ODataComplexValue value2 = new ODataComplexValue(); if (!isCollectionItem) { SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation { TypeName = this.requestInfo.GetServerTypeName(clientTypeAnnotation) }; value2.SetAnnotation<SerializationTypeNameAnnotation>(annotation); } value2.Properties = this.PopulateProperties(clientTypeAnnotation, value, visitedComplexTypeObjects); visitedComplexTypeObjects.Remove(value); return value2; }
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(); }
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); }
internal static string ConvertToUriComplexLiteral(ODataComplexValue complexValue, IEdmModel model, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull<ODataComplexValue>(complexValue, "complexValue"); ExceptionUtils.CheckArgumentNotNull<IEdmModel>(model, "model"); StringBuilder sb = new StringBuilder(); using (TextWriter writer = new StringWriter(sb, CultureInfo.InvariantCulture)) { JsonWriter jsonWriter = new JsonWriter(writer, false); bool writingResponse = false; ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings { Version = new ODataVersion?(version) }; using (ODataJsonOutputContext context = ODataJsonOutputContext.Create(ODataFormat.VerboseJson, jsonWriter, messageWriterSettings, writingResponse, model, null)) { ODataJsonPropertyAndValueSerializer serializer = new ODataJsonPropertyAndValueSerializer(context); serializer.WriteComplexValue(complexValue, null, true, serializer.CreateDuplicatePropertyNamesChecker(), null); } } return sb.ToString(); }