/// <summary> /// This method is for parsing CUD operation payloads which are expected to contain one of the following: /// /// - Single AtomEntry /// This is the typical response we expect in the non-error case. /// - Feed with a single AtomEntry /// This is not valid per OData protocol, but we allowed this in V1/V2 and will continue to accept it since we can still treat it like a single entry. /// - Error /// Parser handles this case as we read the payload, it's not explicitly handled here. /// /// Since we don't control the payload, it may contain something that doesn't fit these requirements, in which case we will throw. /// </summary> /// <param name="reader">the reader for the payload</param> /// <param name="responseInfo">The current ResponseInfo object</param> /// <returns>the AtomEntry that was read</returns> internal static AtomEntry ParseSingleEntityPayload(XmlReader reader, ResponseInfo responseInfo) { using (AtomParser parser = new AtomParser(reader, AtomParser.XElementBuilderCallback, CommonUtil.UriToString(responseInfo.TypeScheme), responseInfo.DataNamespace, responseInfo.BaseUriResolver, responseInfo.MaxProtocolVersion)) { Debug.Assert(parser.DataKind == AtomDataKind.None, "the parser didn't start in the right state"); AtomEntry entry = null; while (parser.Read()) { if (parser.DataKind != AtomDataKind.Feed && parser.DataKind != AtomDataKind.Entry) { throw new InvalidOperationException(Strings.AtomParser_SingleEntry_ExpectedFeedOrEntry); } if (parser.DataKind == AtomDataKind.Entry) { if (entry != null) { throw new InvalidOperationException(Strings.AtomParser_SingleEntry_MultipleFound); } entry = parser.CurrentEntry; } } if (entry == null) { throw new InvalidOperationException(Strings.AtomParser_SingleEntry_NoneFound); } Debug.Assert(parser.DataKind == AtomDataKind.Finished, "the parser didn't end in the right state"); return entry; } }
private void HandleExpandedNavigationProperties(AtomEntry targetEntry, string propertyName, bool isFeed) { Debug.Assert(!this.reader.IsEmptyElement, "the current element has some child content"); if (!ReadChildElement(this.reader, XmlConstants.AtomInlineElementName, XmlConstants.DataWebMetadataNamespace)) { return; } bool emptyInlineCollection = this.reader.IsEmptyElement; object propertyValue = null; if (!emptyInlineCollection) { AtomFeed nestedFeed = null; AtomEntry nestedEntry = null; List<AtomEntry> feedEntries = null; Debug.Assert(this.reader is Xml.XmlWrappingReader, "reader must be a instance of XmlWrappingReader"); Uri readerBaseUri = string.IsNullOrEmpty(this.reader.BaseURI) ? null : new Uri(this.reader.BaseURI, UriKind.Absolute); XmlReader nestedReader = Xml.XmlWrappingReader.CreateReader(readerBaseUri, this.reader.ReadSubtree()); nestedReader.Read(); Debug.Assert(nestedReader.LocalName == "inline", "nestedReader.LocalName == 'inline'"); AtomParser nested = new AtomParser(nestedReader, this.entryCallback, this.typeScheme, this.currentDataNamespace, this.baseUriResolver, this.MaxProtocolVersion); while (nested.Read()) { switch (nested.DataKind) { case AtomDataKind.Feed: feedEntries = new List<AtomEntry>(); nestedFeed = nested.CurrentFeed; propertyValue = nestedFeed; break; case AtomDataKind.Entry: nestedEntry = nested.CurrentEntry; if (feedEntries != null) { feedEntries.Add(nestedEntry); } else { propertyValue = nestedEntry; } break; case AtomDataKind.PagingLinks: // Here the inner feed parser found a paging link, and stored it on nestedFeed.NextPageLink // we are going to add it into a link table and associate // with the collection at AtomMaterializer::Materialize() // Do nothing for now. break; default: throw new InvalidOperationException(Strings.AtomParser_UnexpectedContentUnderExpandedLink); } } if (nestedFeed != null) { Debug.Assert( nestedFeed.Entries == null, "nestedFeed.Entries == null -- otherwise someone initialized this for us"); nestedFeed.Entries = feedEntries; } } AtomContentProperty property = new AtomContentProperty(); property.Name = propertyName; if (emptyInlineCollection || propertyValue == null) { property.IsNull = true; if (isFeed) { property.Feed = new AtomFeed(); property.Feed.Entries = Enumerable.Empty<AtomEntry>(); } else { property.Entry = new AtomEntry(this.MaxProtocolVersion); property.Entry.IsNull = true; } } else { property.Feed = propertyValue as AtomFeed; property.Entry = propertyValue as AtomEntry; } targetEntry.DataValues.Add(property); }