/// <summary> /// Read OData item. /// </summary> /// <param name="reader">The odata reader.</param> /// <param name="itemsStack">The item stack.</param> /// <param name="topLevelItem">The top level item.</param> private static void ReadODataItem(ODataReader reader, Stack <ODataItemWrapper> itemsStack, ref ODataItemWrapper topLevelItem) { Contract.Assert(reader != null); Contract.Assert(itemsStack != null); switch (reader.State) { case ODataReaderState.ResourceStart: ReadResource(reader, itemsStack, ref topLevelItem); break; case ODataReaderState.DeletedResourceStart: ReadDeletedResource(reader, itemsStack); break; case ODataReaderState.ResourceEnd: Contract.Assert(itemsStack.Count > 0, "The resource which is ending should be on the top of the items stack."); ODataResourceWrapper resourceWrapper = itemsStack.Peek() as ODataResourceWrapper; if (resourceWrapper != null) { // Resource could be null Contract.Assert(resourceWrapper.Resource == reader.Item, "The resource should be the same item in the reader."); } itemsStack.Pop(); break; case ODataReaderState.DeletedResourceEnd: Contract.Assert(itemsStack.Count > 0, "The deleted resource which is ending should be on the top of the items stack."); ODataDeletedResourceWrapper deletedResourceWrapper = itemsStack.Peek() as ODataDeletedResourceWrapper; Contract.Assert(deletedResourceWrapper != null, "The top object in the stack should be delete resource wrapper."); Contract.Assert(deletedResourceWrapper.DeletedResource == reader.Item, "The deleted resource should be the same item in the reader."); 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."); { ODataResourceBaseWrapper parentResource = (ODataResourceBaseWrapper)itemsStack.Peek(); parentResource.NestedResourceInfos.Add(nestedResourceInfoWrapper); } itemsStack.Push(nestedResourceInfoWrapper); break; case ODataReaderState.NestedResourceInfoEnd: Contract.Assert(itemsStack.Count > 0, "The nested resource info which is ending should be on the top of the items stack."); ODataNestedResourceInfoWrapper nestedInfoWrapper = itemsStack.Peek() as ODataNestedResourceInfoWrapper; Contract.Assert(nestedInfoWrapper != null, "The top object in the stack should be nested resource info wrapper."); Contract.Assert(nestedInfoWrapper.NestedResourceInfo == reader.Item, "The nested resource info should be the same item in the reader."); itemsStack.Pop(); break; case ODataReaderState.ResourceSetStart: // resource set ReadResourceSet(reader, itemsStack, ref topLevelItem); break; case ODataReaderState.DeltaResourceSetStart: // delta resource set ReadDeltaResourceSet(reader, itemsStack, ref topLevelItem); break; case ODataReaderState.ResourceSetEnd: Contract.Assert(itemsStack.Count > 0, "The resource set which is ending should be on the top of the items stack."); ODataResourceSetWrapper resourceSetWrapper = itemsStack.Peek() as ODataResourceSetWrapper; Contract.Assert(resourceSetWrapper != null, "The top object in the stack should be resource set wrapper."); Contract.Assert(resourceSetWrapper.ResourceSet == reader.Item, "The resource set should be the same item in the reader."); itemsStack.Pop(); break; case ODataReaderState.DeltaResourceSetEnd: Contract.Assert(itemsStack.Count > 0, "The delta resource set which is ending should be on the top of the items stack."); ODataDeltaResourceSetWrapper deltaResourceSetWrapper = itemsStack.Peek() as ODataDeltaResourceSetWrapper; Contract.Assert(deltaResourceSetWrapper != null, "The top object in the stack should be delta resource set wrapper."); Contract.Assert(deltaResourceSetWrapper.DeltaResourceSet == reader.Item, "The delta resource set should be the same item in the reader."); itemsStack.Pop(); break; case ODataReaderState.EntityReferenceLink: ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)reader.Item; Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null."); ODataEntityReferenceLinkWrapper entityReferenceLinkWrapper = new ODataEntityReferenceLinkWrapper(entityReferenceLink); Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item."); { ODataNestedResourceInfoWrapper parentNestedResource = (ODataNestedResourceInfoWrapper)itemsStack.Peek(); Contract.Assert(parentNestedResource.NestedResourceSet == null, "Each reference nested property can not contain resource set as its direct child."); Contract.Assert(parentNestedResource.NestedResource == null, "Each reference nested property can not contain resource as its direct child."); parentNestedResource.AppendReferenceLink(entityReferenceLinkWrapper); } break; case ODataReaderState.DeltaLink: // added link case ODataReaderState.DeltaDeletedLink: // deleted link ODataDeltaLinkBaseWrapper linkBaseWrapper; if (ODataReaderState.DeltaLink == reader.State) { ODataDeltaLink deltaLink = (ODataDeltaLink)reader.Item; Contract.Assert(deltaLink != null, "Delta link should never be null."); linkBaseWrapper = new ODataDeltaLinkWrapper(deltaLink); } else { ODataDeltaDeletedLink deltaDeletedLink = (ODataDeltaDeletedLink)reader.Item; Contract.Assert(deltaDeletedLink != null, "Delta deleted link should never be null."); linkBaseWrapper = new ODataDeltaDeletedLinkWrapper(deltaDeletedLink); } Contract.Assert(itemsStack.Count > 0, "Delta link should never be reported as top-level item."); // Should never add a delta link to a non-delta resource set. ODataDeltaResourceSetWrapper linkResourceSetWrapper = (ODataDeltaResourceSetWrapper)itemsStack.Peek(); Contract.Assert(linkResourceSetWrapper != null, "ODataDeltaResourceSetWrapper for delta link should not be null."); linkResourceSetWrapper.DeltaLinks.Add(linkBaseWrapper); break; default: Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state."); break; } }
/// <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 new ArgumentNullException(nameof(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); }