public void ApplyNestedProperty_UsesThePropertyAlias_ForResourceWrapper() { // Arrange CustomersModelWithInheritance model = new CustomersModelWithInheritance(); model.Model.SetAnnotationValue(model.Customer, new ClrTypeAnnotation(typeof(Customer))); model.Model.SetAnnotationValue(model.Order, new ClrTypeAnnotation(typeof(Order))); model.Model.SetAnnotationValue( model.Order.FindProperty("Customer"), new ClrPropertyInfoAnnotation(typeof(Order).GetProperty("AliasedCustomer"))); ODataResource resource = new ODataResource { Properties = new[] { new ODataProperty { Name = "ID", Value = 42 } } }; Order order = new Order(); ODataNestedResourceInfoWrapper resourceInfoWrapper = new ODataNestedResourceInfoWrapper(new ODataNestedResourceInfo { Name = "Customer" }); resourceInfoWrapper.NestedItems.Add(new ODataResourceWrapper(resource)); ODataDeserializerContext context = new ODataDeserializerContext { Model = model.Model }; // Act new ODataResourceDeserializer(_deserializerProvider) .ApplyNestedProperty(order, resourceInfoWrapper, model.Order.AsReference(), context); // Assert Assert.Equal(order.AliasedCustomer.ID, 42); }
public void ApplyNestedProperty_ThrowsArgumentNull_EntityResource() { // Arrange var deserializer = new ODataResourceDeserializer(_deserializerProvider); ODataNestedResourceInfoWrapper resourceInfoWrapper = new ODataNestedResourceInfoWrapper(new ODataNestedResourceInfo()); // Act & Assert Assert.ThrowsArgumentNull( () => deserializer.ApplyNestedProperty(resource: null, resourceInfoWrapper: resourceInfoWrapper, structuredType: _productEdmType, readContext: _readContext), "resource"); }
public void ApplyNestedProperty_ThrowsODataException_NavigationPropertyNotfound() { // Arrange var deserializer = new ODataResourceDeserializer(_deserializerProvider); ODataNestedResourceInfoWrapper resourceInfoWrapper = new ODataNestedResourceInfoWrapper(new ODataNestedResourceInfo { Name = "SomeProperty" }); // Act & Assert Assert.Throws <ODataException>( () => deserializer.ApplyNestedProperty(42, resourceInfoWrapper, _productEdmType, _readContext), "Cannot find nested property 'SomeProperty' on the resource type 'ODataDemo.Product'."); }
public void ApplyNestedProperty_ThrowsODataException_WhenPatchingCollectionNavigationProperty() { // Arrange var deserializer = new ODataResourceDeserializer(_deserializerProvider); ODataNestedResourceInfoWrapper resourceInfoWrapper = new ODataNestedResourceInfoWrapper(new ODataNestedResourceInfo { Name = "Products" }); resourceInfoWrapper.NestedItems.Add(new ODataResourceSetWrapper(new ODataResourceSet())); _readContext.ResourceType = typeof(Delta <Supplier>); // Act & Assert Assert.Throws <ODataException>( () => deserializer.ApplyNestedProperty(42, resourceInfoWrapper, _supplierEdmType, _readContext), "Cannot apply PATCH to navigation property 'Products' on entity type 'ODataDemo.Supplier'."); }
/// <summary> /// Deserializes the nested property from <paramref name="resourceInfoWrapper"/> into <paramref name="resource"/>. /// </summary> /// <param name="resource">The object into which the nested property should be read.</param> /// <param name="resourceInfoWrapper">The nested resource info.</param> /// <param name="structuredType">The type of the resource.</param> /// <param name="readContext">The deserializer context.</param> public virtual void ApplyNestedProperty(object resource, ODataNestedResourceInfoWrapper resourceInfoWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext) { if (resource == null) { throw Error.ArgumentNull("resource"); } if (resourceInfoWrapper == null) { throw Error.ArgumentNull("resourceInfoWrapper"); } IEdmProperty edmProperty = structuredType.FindProperty(resourceInfoWrapper.NestedResourceInfo.Name); if (edmProperty == null) { if (!structuredType.IsOpen()) { throw new ODataException( Error.Format(SRResources.NestedPropertyNotfound, resourceInfoWrapper.NestedResourceInfo.Name, structuredType.FullName())); } } foreach (ODataItemBase childItem in resourceInfoWrapper.NestedItems) { // it maybe null. if (childItem == null) { if (edmProperty == null) { // for the dynamic, OData.net has a bug. see https://github.com/OData/odata.net/issues/977 ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, null, readContext); } else { ApplyResourceInNestedProperty(edmProperty, resource, null, readContext); } } ODataEntityReferenceLinkBase entityReferenceLink = childItem as ODataEntityReferenceLinkBase; if (entityReferenceLink != null) { // ignore entity reference links. continue; } ODataResourceSetWrapper resourceSetWrapper = childItem as ODataResourceSetWrapper; if (resourceSetWrapper != null) { if (edmProperty == null) { ApplyDynamicResourceSetInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, resourceSetWrapper, readContext); } else { ApplyResourceSetInNestedProperty(edmProperty, resource, resourceSetWrapper, readContext); } continue; } // It must be resource by now. ODataResourceWrapper resourceWrapper = (ODataResourceWrapper)childItem; if (resourceWrapper != null) { if (edmProperty == null) { ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, resourceWrapper, readContext); } else { ApplyResourceInNestedProperty(edmProperty, resource, resourceWrapper, readContext); } } } }
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> /// 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); }