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;
        }
Exemple #4
0
 internal static IEnumerable<ODataProperty> GetComplexValueProperties(EpmValueCache epmValueCache, ODataComplexValue complexValue, bool writingContent)
 {
     if (epmValueCache == null)
     {
         return complexValue.Properties;
     }
     return epmValueCache.GetComplexValueProperties(complexValue, writingContent);
 }
Exemple #5
0
 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);
        }
Exemple #11
0
 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);
        }
Exemple #17
0
 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);
        }
Exemple #20
0
        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();
        }
Exemple #25
0
        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));
            }
        }
Exemple #26
0
        /// <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);
        }
Exemple #27
0
 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();
 }
Exemple #29
0
 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();
 }