Exemple #1
0
        public void ReadResource_CanReadDynamicPropertiesForOpenEntityType()
        {
            // Arrange
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

            builder.EntityType <SimpleOpenCustomer>();
            builder.EnumType <SimpleEnum>();
            IEdmModel model = builder.GetEdmModel();

            IEdmEntityTypeReference customerTypeReference = model.GetEdmTypeReference(typeof(SimpleOpenCustomer)).AsEntity();

            var deserializer = new ODataResourceDeserializer(_deserializerProvider);

            ODataEnumValue enumValue = new ODataEnumValue("Third", typeof(SimpleEnum).FullName);

            ODataResource[] complexResources =
            {
                new ODataResource
                {
                    TypeName   = typeof(SimpleOpenAddress).FullName,
                    Properties = new[]
                    {
                        // declared properties
                        new ODataProperty {
                            Name = "Street", Value = "Street 1"
                        },
                        new ODataProperty {
                            Name = "City", Value = "City 1"
                        },

                        // dynamic properties
                        new ODataProperty
                        {
                            Name  = "DateTimeProperty",
                            Value = new DateTimeOffset(new DateTime(2014, 5, 6))
                        }
                    }
                },
                new ODataResource
                {
                    TypeName   = typeof(SimpleOpenAddress).FullName,
                    Properties = new[]
                    {
                        // declared properties
                        new ODataProperty {
                            Name = "Street", Value = "Street 2"
                        },
                        new ODataProperty {
                            Name = "City", Value = "City 2"
                        },

                        // dynamic properties
                        new ODataProperty
                        {
                            Name  = "ArrayProperty",
                            Value = new ODataCollectionValue{
                                TypeName = "Collection(Edm.Int32)", Items = new[]{                                         1, 2, 3, 4 }.Cast <object>()
                            }
                        }
                    }
                }
            };

            ODataResource odataResource = new ODataResource
            {
                Properties = new[]
                {
                    // declared properties
                    new ODataProperty {
                        Name = "CustomerId", Value = 991
                    },
                    new ODataProperty {
                        Name = "Name", Value = "Name #991"
                    },

                    // dynamic properties
                    new ODataProperty {
                        Name = "GuidProperty", Value = new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA")
                    },
                    new ODataProperty {
                        Name = "EnumValue", Value = enumValue
                    },
                },
                TypeName = typeof(SimpleOpenCustomer).FullName
            };

            ODataDeserializerContext readContext = new ODataDeserializerContext()
            {
                Model = model
            };

            ODataResourceWrapper topLevelResourceWrapper = new ODataResourceWrapper(odataResource);

            ODataNestedResourceInfo resourceInfo = new ODataNestedResourceInfo
            {
                IsCollection = true,
                Name         = "CollectionProperty"
            };
            ODataNestedResourceInfoWrapper resourceInfoWrapper = new ODataNestedResourceInfoWrapper(resourceInfo);
            ODataResourceSetWrapper        resourceSetWrapper  = new ODataResourceSetWrapper(new ODataResourceSet
            {
                TypeName = String.Format("Collection({0})", typeof(SimpleOpenAddress).FullName)
            });

            foreach (var complexResource in complexResources)
            {
                resourceSetWrapper.Resources.Add(new ODataResourceWrapper(complexResource));
            }
            resourceInfoWrapper.NestedItems.Add(resourceSetWrapper);
            topLevelResourceWrapper.NestedResourceInfos.Add(resourceInfoWrapper);

            // Act
            SimpleOpenCustomer customer = deserializer.ReadResource(topLevelResourceWrapper, customerTypeReference, readContext)
                                          as SimpleOpenCustomer;

            // Assert
            Assert.NotNull(customer);

            // Verify the declared properties
            Assert.Equal(991, customer.CustomerId);
            Assert.Equal("Name #991", customer.Name);

            // Verify the dynamic properties
            Assert.NotNull(customer.CustomerProperties);
            Assert.Equal(3, customer.CustomerProperties.Count());
            Assert.Equal(new Guid("181D3A20-B41A-489F-9F15-F91F0F6C9ECA"), customer.CustomerProperties["GuidProperty"]);
            Assert.Equal(SimpleEnum.Third, customer.CustomerProperties["EnumValue"]);

            // Verify the dynamic collection property
            var collectionValues = Assert.IsType <List <SimpleOpenAddress> >(customer.CustomerProperties["CollectionProperty"]);

            Assert.NotNull(collectionValues);
            Assert.Equal(2, collectionValues.Count());

            Assert.Equal(new DateTimeOffset(new DateTime(2014, 5, 6)), collectionValues[0].Properties["DateTimeProperty"]);
            Assert.Equal(new List <int> {
                1, 2, 3, 4
            }, collectionValues[1].Properties["ArrayProperty"]);
        }
        /// <summary>
        /// Deserializes the given <paramref name="resourceWrapper"/> under the given <paramref name="readContext"/>.
        /// </summary>
        /// <param name="resourceWrapper">The OData resource to deserialize.</param>
        /// <param name="structuredType">The type of the resource to deserialize.</param>
        /// <param name="readContext">The deserializer context.</param>
        /// <returns>The deserialized resource.</returns>
        public virtual object ReadResource(ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType,
                                           ODataDeserializerContext readContext)
        {
            if (resourceWrapper == null)
            {
                throw Error.ArgumentNull("resourceWrapper");
            }

            if (readContext == null)
            {
                throw Error.ArgumentNull("readContext");
            }

            if (!String.IsNullOrEmpty(resourceWrapper.Resource.TypeName) && structuredType.FullName() != resourceWrapper.Resource.TypeName)
            {
                // received a derived type in a base type deserializer. delegate it to the appropriate derived type deserializer.
                IEdmModel model = readContext.Model;

                if (model == null)
                {
                    throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext);
                }

                IEdmStructuredType actualType = model.FindType(resourceWrapper.Resource.TypeName) as IEdmStructuredType;
                if (actualType == null)
                {
                    throw new ODataException(Error.Format(SRResources.ResourceTypeNotInModel, resourceWrapper.Resource.TypeName));
                }

                if (actualType.IsAbstract)
                {
                    string message = Error.Format(SRResources.CannotInstantiateAbstractResourceType, resourceWrapper.Resource.TypeName);
                    throw new ODataException(message);
                }

                IEdmTypeReference actualStructuredType;
                IEdmEntityType    actualEntityType = actualType as IEdmEntityType;
                if (actualEntityType != null)
                {
                    actualStructuredType = new EdmEntityTypeReference(actualEntityType, isNullable: false);
                }
                else
                {
                    actualStructuredType = new EdmComplexTypeReference(actualType as IEdmComplexType, isNullable: false);
                }

                ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualStructuredType);
                if (deserializer == null)
                {
                    throw new SerializationException(
                              Error.Format(SRResources.TypeCannotBeDeserialized, actualEntityType.FullName(), typeof(ODataMediaTypeFormatter).Name));
                }

                object resource = deserializer.ReadInline(resourceWrapper, actualStructuredType, readContext);

                EdmStructuredObject structuredObject = resource as EdmStructuredObject;
                if (structuredObject != null)
                {
                    structuredObject.ExpectedEdmType = structuredType.StructuredDefinition();
                }

                return(resource);
            }
            else
            {
                object resource = CreateResourceInstance(structuredType, readContext);
                ApplyResourceProperties(resource, resourceWrapper, structuredType, readContext);
                return(resource);
            }
        }
        /// <summary>
        /// Reads a <see cref="ODataResource"/> or <see cref="ODataResourceSet"/> object.
        /// </summary>
        /// <param name="reader">The OData reader to read from.</param>
        /// <returns>The read resource or resource set.</returns>
        public static ODataItemBase ReadResourceOrResourceSet(this ODataReader reader)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("reader");
            }

            ODataItemBase         topLevelItem = null;
            Stack <ODataItemBase> itemsStack   = new Stack <ODataItemBase>();

            while (reader.Read())
            {
                switch (reader.State)
                {
                case ODataReaderState.ResourceStart:
                    ODataResource        resource        = (ODataResource)reader.Item;
                    ODataResourceWrapper resourceWrapper = null;
                    if (resource != null)
                    {
                        resourceWrapper = new ODataResourceWrapper(resource);
                    }

                    if (itemsStack.Count == 0)
                    {
                        Contract.Assert(resource != null, "The top-level resource can never be null.");
                        topLevelItem = resourceWrapper;
                    }
                    else
                    {
                        ODataItemBase           parentItem        = itemsStack.Peek();
                        ODataResourceSetWrapper parentResourceSet = parentItem as ODataResourceSetWrapper;
                        if (parentResourceSet != null)
                        {
                            parentResourceSet.Resources.Add(resourceWrapper);
                        }
                        else
                        {
                            ODataNestedResourceInfoWrapper parentNestedResource = (ODataNestedResourceInfoWrapper)parentItem;
                            Contract.Assert(parentNestedResource.NestedResourceInfo.IsCollection == false, "Only singleton nested properties can contain resource as their child.");
                            Contract.Assert(parentNestedResource.NestedItems.Count == 0, "Each nested property can contain only one resource as its direct child.");
                            parentNestedResource.NestedItems.Add(resourceWrapper);
                        }
                    }

                    itemsStack.Push(resourceWrapper);
                    break;

                case ODataReaderState.ResourceEnd:
                    Contract.Assert(
                        itemsStack.Count > 0 && (reader.Item == null || itemsStack.Peek().Item == reader.Item),
                        "The resource which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.NestedResourceInfoStart:
                    ODataNestedResourceInfo nestedResourceInfo = (ODataNestedResourceInfo)reader.Item;
                    Contract.Assert(nestedResourceInfo != null, "nested resource info should never be null.");

                    ODataNestedResourceInfoWrapper nestedResourceInfoWrapper = new ODataNestedResourceInfoWrapper(nestedResourceInfo);
                    Contract.Assert(itemsStack.Count > 0, "nested resource info can't appear as top-level item.");
                    {
                        ODataResourceWrapper parentResource = (ODataResourceWrapper)itemsStack.Peek();
                        parentResource.NestedResourceInfos.Add(nestedResourceInfoWrapper);
                    }

                    itemsStack.Push(nestedResourceInfoWrapper);
                    break;

                case ODataReaderState.NestedResourceInfoEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item,
                                    "The nested resource info which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.ResourceSetStart:
                    ODataResourceSet resourceSet = (ODataResourceSet)reader.Item;
                    Contract.Assert(resourceSet != null, "ResourceSet should never be null.");

                    ODataResourceSetWrapper resourceSetWrapper = new ODataResourceSetWrapper(resourceSet);
                    if (itemsStack.Count > 0)
                    {
                        ODataNestedResourceInfoWrapper parentNestedResourceInfo = (ODataNestedResourceInfoWrapper)itemsStack.Peek();
                        Contract.Assert(parentNestedResourceInfo != null, "this has to be an inner resource set. inner resource sets always have a nested resource info.");
                        Contract.Assert(parentNestedResourceInfo.NestedResourceInfo.IsCollection == true, "Only collection nested properties can contain resource set as their child.");
                        parentNestedResourceInfo.NestedItems.Add(resourceSetWrapper);
                    }
                    else
                    {
                        topLevelItem = resourceSetWrapper;
                    }

                    itemsStack.Push(resourceSetWrapper);
                    break;

                case ODataReaderState.ResourceSetEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The resource set which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.EntityReferenceLink:
                    ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)reader.Item;
                    Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null.");
                    ODataEntityReferenceLinkBase entityReferenceLinkWrapper = new ODataEntityReferenceLinkBase(entityReferenceLink);

                    Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                    {
                        ODataNestedResourceInfoWrapper parentNavigationLink = (ODataNestedResourceInfoWrapper)itemsStack.Peek();
                        parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper);
                    }

                    break;

                default:
                    Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state.");
                    break;
                }
            }

            Contract.Assert(reader.State == ODataReaderState.Completed, "We should have consumed all of the input by now.");
            Contract.Assert(topLevelItem != null, "A top level resource or resource set should have been read by now.");
            return(topLevelItem);
        }