/// <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); } } } }
private static void ReadCollectionItem(ODataReader reader, Stack <ODataItemBase> itemsStack, ref ODataItemBase topLevelItem) { 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 = parentItem as ODataNestedResourceInfoWrapper; if (parentNestedResource != null) { 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); } else { ODataDeltaResourceSetWrapper parentDeltaSetResource = (ODataDeltaResourceSetWrapper)parentItem; parentDeltaSetResource.Resources.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; case ODataReaderState.DeltaResourceSetStart: ODataDeltaResourceSet deltaResourceSet = (ODataDeltaResourceSet)reader.Item; Contract.Assert(deltaResourceSet != null, "ResourceSet should never be null."); ODataDeltaResourceSetWrapper deltaResourceSetWrapper = new ODataDeltaResourceSetWrapper(deltaResourceSet); 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(deltaResourceSetWrapper); } else { topLevelItem = deltaResourceSetWrapper; } itemsStack.Push(deltaResourceSetWrapper); break; case ODataReaderState.DeltaResourceSetEnd: 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.DeletedResourceStart: ODataDeletedResource deletedResource = (ODataDeletedResource)reader.Item; if (deletedResource != null) { // Note: I expect that deleted resourced will not have other nested resources ODataDeletedResourceWrapper deletedResourceWrapper = new ODataDeletedResourceWrapper(deletedResource); ODataItemBase parentItem = itemsStack.Peek(); ODataDeltaResourceSetWrapper parentDeltaSetResource = parentItem as ODataDeltaResourceSetWrapper; if (parentDeltaSetResource != null) { parentDeltaSetResource.DeletedResources.Add(deletedResourceWrapper); } } break; case ODataReaderState.DeletedResourceEnd: break; default: Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state."); break; } }
/// <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())); } 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); } }