/// <summary> /// Writes an OData feed. /// </summary> /// <param name="writer">The ODataWriter that will write the feed.</param> /// <param name="entityType">The type of the entity in the feed.</param> /// <param name="entries">The items from the data store to write to the feed.</param> /// <param name="entitySet">The entity set in the model that the feed belongs to.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <param name="selectExpandClause">The SelectExpandClause.</param> public static void WriteFeed(ODataWriter writer, IEdmEntityType entityType, IEnumerable entries, IEdmEntitySetBase entitySet, ODataVersion targetVersion, SelectExpandClause selectExpandClause, long?count, Uri deltaLink, Uri nextPageLink, Dictionary <string, string> incomingHeaders = null) { var feed = new ODataFeed { Id = entitySet == null ? null : new Uri(ServiceConstants.ServiceBaseUri, entitySet.Name), DeltaLink = deltaLink, NextPageLink = nextPageLink }; if (entitySet == null) { feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceEntityTypeName = entityType.FullTypeName(), NavigationSourceName = null, NavigationSourceKind = EdmNavigationSourceKind.UnknownEntitySet, IsFromCollection = true }); } if (count.HasValue) { feed.Count = count; } writer.WriteStart(feed); foreach (var element in entries) { WriteEntry(writer, element, entitySet, targetVersion, selectExpandClause, incomingHeaders); } writer.WriteEnd(); }
public void ShouldBeAbleToSetTheFeedSerializationInfo() { ODataFeed feed = new ODataFeed(); ODataFeedAndEntrySerializationInfo serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.base", ExpectedTypeName = "ns.expected" }; feed.SetSerializationInfo(serializationInfo); feed.SerializationInfo.Should().BeSameAs(serializationInfo); }
public void SetFeedSerializationInfoShouldThrowOnNullFeed() { ODataFeed feed = null; Action action = () => feed.SetSerializationInfo(null); action.ShouldThrow <ArgumentNullException>().WithMessage("feed", ComparisonMode.Substring); }
private string WriteAndVerifyOrderFeed(StreamResponseMessage responseMessage, ODataWriter odataWriter, bool hasModel, string mimeType) { var orderFeed = new ODataFeed() { Id = new Uri(this.ServiceUri + "Order"), NextPageLink = new Uri(this.ServiceUri + "Order?$skiptoken=-9"), }; if (!hasModel) { orderFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Order", NavigationSourceEntityTypeName = NameSpace + "Order" }); } odataWriter.WriteStart(orderFeed); var orderEntry1 = WritePayloadHelper.CreateOrderEntry1(hasModel); odataWriter.WriteStart(orderEntry1); var orderEntry1Navigation1 = new ODataNavigationLink() { Name = "Customer", IsCollection = false, Url = new Uri(this.ServiceUri + "Order(-10)/Customer") }; odataWriter.WriteStart(orderEntry1Navigation1); odataWriter.WriteEnd(); var orderEntry1Navigation2 = new ODataNavigationLink() { Name = "Login", IsCollection = false, Url = new Uri(this.ServiceUri + "Order(-10)/Login") }; odataWriter.WriteStart(orderEntry1Navigation2); odataWriter.WriteEnd(); // Finish writing orderEntry1. odataWriter.WriteEnd(); var orderEntry2 = WritePayloadHelper.CreateOrderEntry2(hasModel); odataWriter.WriteStart(orderEntry2); var orderEntry2Navigation1 = new ODataNavigationLink() { Name = "Customer", IsCollection = false, Url = new Uri(this.ServiceUri + "Order(-9)/Customer") }; odataWriter.WriteStart(orderEntry2Navigation1); odataWriter.WriteEnd(); var orderEntry2Navigation2 = new ODataNavigationLink() { Name = "Login", IsCollection = false, Url = new Uri(this.ServiceUri + "Order(-9)/Login") }; odataWriter.WriteStart(orderEntry2Navigation2); odataWriter.WriteEnd(); // Finish writing orderEntry2. odataWriter.WriteEnd(); // Finish writing the feed. odataWriter.WriteEnd(); // Some very basic verification for the payload. bool verifyFeedCalled = false; bool verifyEntryCalled = false; bool verifyNavigationCalled = false; Action <ODataFeed> verifyFeed = (feed) => { Assert.IsNotNull(feed.NextPageLink, "feed.NextPageLink"); verifyFeedCalled = true; }; Action <ODataEntry> verifyEntry = (entry) => { Assert.AreEqual(3, entry.Properties.Count(), "entry.Properties.Count"); verifyEntryCalled = true; }; Action <ODataNavigationLink> verifyNavigation = (navigation) => { Assert.IsTrue(navigation.Name == "Customer" || navigation.Name == "Login", "navigation.Name"); verifyNavigationCalled = true; }; Stream stream = responseMessage.GetStream(); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { stream.Seek(0, SeekOrigin.Begin); WritePayloadHelper.ReadAndVerifyFeedEntryMessage(true, responseMessage, WritePayloadHelper.OrderSet, WritePayloadHelper.OrderType, verifyFeed, verifyEntry, verifyNavigation); Assert.IsTrue(verifyFeedCalled && verifyEntryCalled && verifyNavigationCalled, "Verification action not called."); } return(WritePayloadHelper.ReadStreamContent(stream)); }
public void ShouldBeAbleToWriteFeedAndEntryResponseInJsonLightWithoutModel() { const string expectedPayload = "{" + "\"@odata.context\":\"http://www.example.com/$metadata#Customers/NS.VIPCustomer\"," + "\"value\":[" + "{" + "\"Name\":\"Bob\"," + "\"[email protected]\":\"MostRecentOrder\"," + "\"MostRecentOrder\":{\"OrderId\":101}" + "}" + "]" + "}"; var writerSettings = new ODataMessageWriterSettings { DisableMessageStreamDisposal = true }; writerSettings.SetContentType(ODataFormat.Json); writerSettings.ODataUri = new ODataUri() { ServiceRoot = new Uri("http://www.example.com") }; MemoryStream stream = new MemoryStream(); IODataResponseMessage responseMessage = new InMemoryMessage { StatusCode = 200, Stream = stream }; // Write payload using (var messageWriter = new ODataMessageWriter(responseMessage, writerSettings)) { var odataWriter = messageWriter.CreateODataFeedWriter(); // Create customers feed with serializtion info to write odata.metadata. var customersFeed = new ODataFeed(); customersFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Customers", NavigationSourceEntityTypeName = "NS.Customer", ExpectedTypeName = "NS.VIPCustomer" }); // Write customers feed. odataWriter.WriteStart(customersFeed); // Write VIP customer { // Create VIP customer, don't need to pass in serialization info since the writer knows the context from the feed scope. var vipCustomer = new ODataEntry { TypeName = "NS.VIPCustomer" }; var customerKey = new ODataProperty { Name = "Name", Value = "Bob" }; // Provide serialization info at the property level to compute the edit link. customerKey.SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }); vipCustomer.Properties = new[] { customerKey }; // Write customer entry. odataWriter.WriteStart(vipCustomer); // Write expanded most recent order { // No API to set serialization info on ODataNavigationLink since what we are adding on ODataFeed and ODataEntry should be sufficient for the 5.5 release. var navigationLink = new ODataNavigationLink { Name = "MostRecentOrder", IsCollection = false, Url = new Uri("MostRecentOrder", UriKind.Relative) }; odataWriter.WriteStart(navigationLink); // Write the most recent customer. { var mostRecentOrder = new ODataEntry { TypeName = "NS.Order" }; // Add serialization info so we can computer links. mostRecentOrder.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Orders", NavigationSourceEntityTypeName = "NS.Order", ExpectedTypeName = "NS.Order" }); var orderKey = new ODataProperty { Name = "OrderId", Value = 101 }; // Provide serialization info at the property level to compute the edit link. orderKey.SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }); mostRecentOrder.Properties = new[] { orderKey }; // Write order entry. odataWriter.WriteStart(mostRecentOrder); odataWriter.WriteEnd(); } // End navigationLink. odataWriter.WriteEnd(); } // End customer entry. odataWriter.WriteEnd(); } // End customers feed. odataWriter.WriteEnd(); } stream.Position = 0; string payload = (new StreamReader(stream)).ReadToEnd(); payload.Should().Be(expectedPayload); }
public void WritingInMinimalMetadataModeWithExpandAndProjectionWithModelWhenAutoComputePayloadMetadataInJsonIsTrue() { const string expectedPayload = "{" + "\"@odata.context\":\"http://example.com/$metadata#EntitySet(StreamProp1,Namespace.AlwaysBindableAction1,Namespace.AlwaysBindableFunction1,DeferredNavLink,ExpandedNavLink,ExpandedNavLink(StreamProp1,Namespace.AlwaysBindableAction1,ExpandedNavLink,ExpandedNavLink(StreamProp2,Namespace.AlwaysBindableAction1)))\"," + "\"value\":[" + "{" + "\"ID\":123," + "\"Name\":\"Bob\"," + "\"[email protected]\":\"http://example.com/expanded/association\"," + "\"[email protected]\":\"http://example.com/expanded/navigation\"," + "\"ExpandedNavLink\":[" + "{" + "\"ID\":234," + "\"Name\":\"Foo\"," + "\"ExpandedNavLink\":[" + "{" + "\"ID\":345," + "\"Name\":\"Bar\"," + "\"#Container.AlwaysBindableAction1\":{}" + "}]," + "\"#Container.AlwaysBindableAction1\":{}" + "}]," + "\"#Container.AlwaysBindableAction1\":{}," + "\"#Container.AlwaysBindableFunction1\":{}" + "}]" + "}"; ODataFeedAndEntrySerializationInfo serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = EntitySet.Name, NavigationSourceEntityTypeName = EntityType.FullName(), ExpectedTypeName = EntityType.FullName() }; var feed = new ODataFeed(); feed.SetSerializationInfo(serializationInfo); this.entryWithOnlyData = new ODataEntry { TypeName = EntityType.FullName(), MediaResource = new ODataStreamReferenceValue(), Properties = new[] { new ODataProperty { Name = "ID", Value = 123, SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }}, new ODataProperty { Name = "Name", Value = "Bob", SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }}, new ODataProperty { Name = "StreamProp1", Value = new ODataStreamReferenceValue() } }, }; this.entryWithOnlyData.AddAction(new ODataAction { Metadata = new Uri("http://example.com/$metadata#Container.AlwaysBindableAction1") }); this.entryWithOnlyData.AddFunction(new ODataFunction { Metadata = new Uri("#Container.AlwaysBindableFunction1", UriKind.Relative) }); this.entryWithOnlyData2 = new ODataEntry { TypeName = EntityType.FullName(), MediaResource = new ODataStreamReferenceValue(), Properties = new[] { new ODataProperty { Name = "ID", Value = 234, SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }}, new ODataProperty { Name = "Name", Value = "Foo", SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }}, new ODataProperty { Name = "StreamProp1", Value = new ODataStreamReferenceValue() } }, }; this.entryWithOnlyData2.AddAction(new ODataAction { Metadata = new Uri("http://example.com/$metadata#Container.AlwaysBindableAction1") }); this.entryWithOnlyData3 = new ODataEntry { TypeName = EntityType.FullName(), MediaResource = new ODataStreamReferenceValue(), Properties = new[] { new ODataProperty { Name = "ID", Value = 345, SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }}, new ODataProperty { Name = "Name", Value = "Bar", SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }}, new ODataProperty { Name = "StreamProp2", Value = new ODataStreamReferenceValue() } }, }; this.entryWithOnlyData3.AddAction(new ODataAction { Metadata = new Uri("http://example.com/$metadata#Container.AlwaysBindableAction1") }); ODataItem[] itemsToWrite = new ODataItem[] { feed, this.entryWithOnlyData, this.expandedNavLinkWithPayloadMetadata, feed, this.entryWithOnlyData2, this.navLinkWithoutPayloadMetadata, this.expandedNavLinkWithoutPayloadMetadata, feed, this.entryWithOnlyData3 }; const string selectClause = "StreamProp1,Namespace.AlwaysBindableAction1,Namespace.AlwaysBindableFunction1,DeferredNavLink"; const string expandClause = "ExpandedNavLink($select=StreamProp1,Namespace.AlwaysBindableAction1;$expand=ExpandedNavLink($select=StreamProp2,Namespace.AlwaysBindableAction1))"; this.GetWriterOutputForContentTypeAndKnobValue("application/json;odata.metadata=minimal", true, itemsToWrite, edmModel: Model, edmEntitySet: null, edmEntityType: EntityType, selectClause: selectClause, expandClause: expandClause) .Should().Be(expectedPayload); }
public void WritingInFullMetadataModeWithExpandAndProjectionWithMissingStreamAndActionAndFunctionWhenAutoComputePayloadMetadataInJsonIsTrue() { const string expectedPayload = "{" + "\"@odata.context\":\"http://example.com/$metadata#EntitySet(StreamProp1,Namespace.AlwaysBindableAction1,Namespace.AlwaysBindableFunction1,DeferredNavLink,ExpandedNavLink,ExpandedNavLink(StreamProp1,Namespace.AlwaysBindableAction1,ExpandedNavLink,ExpandedNavLink(StreamProp2,Namespace.AlwaysBindableAction1)))\"," + "\"value\":[" + "{" + "\"@odata.type\":\"#Namespace.EntityType\"," + "\"@odata.id\":\"EntitySet(123)\"," + "\"@odata.etag\":\"W/\\\"'Bob'\\\"\"," + "\"@odata.editLink\":\"EntitySet(123)\"," + "\"@odata.mediaEditLink\":\"EntitySet(123)/$value\"," + "\"ID\":123," + "\"Name\":\"Bob\"," + "\"[email protected]\":\"http://example.com/expanded/association\"," + "\"[email protected]\":\"http://example.com/expanded/navigation\"," + "\"ExpandedNavLink\":[" + "{" + "\"@odata.type\":\"#Namespace.EntityType\"," + "\"@odata.id\":\"EntitySet(234)\"," + "\"@odata.etag\":\"W/\\\"'Foo'\\\"\"," + "\"@odata.editLink\":\"EntitySet(234)\"," + "\"@odata.mediaEditLink\":\"EntitySet(234)/$value\"," + "\"ID\":234," + "\"Name\":\"Foo\"," + "\"[email protected]\":\"http://example.com/EntitySet(234)/DeferredNavLink/$ref\"," + "\"[email protected]\":\"http://example.com/EntitySet(234)/DeferredNavLink\"," + "\"[email protected]\":\"http://example.com/EntitySet(234)/ExpandedNavLink/$ref\"," + "\"[email protected]\":\"http://example.com/EntitySet(234)/ExpandedNavLink\"," + "\"ExpandedNavLink\":[" + "{" + "\"@odata.type\":\"#Namespace.EntityType\"," + "\"@odata.id\":\"EntitySet(345)\"," + "\"@odata.etag\":\"W/\\\"'Bar'\\\"\"," + "\"@odata.editLink\":\"EntitySet(345)\"," + "\"@odata.mediaEditLink\":\"EntitySet(345)/$value\"," + "\"ID\":345," + "\"Name\":\"Bar\"" + "}]" + "}]" + "}]" + "}"; ODataFeedAndEntrySerializationInfo serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = EntitySet.Name, NavigationSourceEntityTypeName = EntityType.FullName(), ExpectedTypeName = EntityType.FullName() }; var feed = new ODataFeed(); feed.SetSerializationInfo(serializationInfo); this.entryWithOnlyData.TypeName = EntityType.FullName(); this.entryWithOnlyData.MediaResource = new ODataStreamReferenceValue(); this.entryWithOnlyData.Properties.First(p => p.Name == "ID").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }); this.entryWithOnlyData.Properties.First(p => p.Name == "Name").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }); this.entryWithOnlyData2.TypeName = EntityType.FullName(); this.entryWithOnlyData2.MediaResource = new ODataStreamReferenceValue(); this.entryWithOnlyData2.Properties.First(p => p.Name == "ID").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }); this.entryWithOnlyData2.Properties.First(p => p.Name == "Name").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }); this.entryWithOnlyData3.TypeName = EntityType.FullName(); this.entryWithOnlyData3.MediaResource = new ODataStreamReferenceValue(); this.entryWithOnlyData3.Properties.First(p => p.Name == "ID").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key }); this.entryWithOnlyData3.Properties.First(p => p.Name == "Name").SetSerializationInfo(new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag }); ODataItem[] itemsToWrite = new ODataItem[] { feed, this.entryWithOnlyData, this.expandedNavLinkWithPayloadMetadata, feed, this.entryWithOnlyData2, this.navLinkWithoutPayloadMetadata, this.expandedNavLinkWithoutPayloadMetadata, feed, this.entryWithOnlyData3 }; const string selectClause = "StreamProp1,Namespace.AlwaysBindableAction1,Namespace.AlwaysBindableFunction1,DeferredNavLink"; const string expandClause = "ExpandedNavLink($select=StreamProp1,Namespace.AlwaysBindableAction1;$expand=ExpandedNavLink($select=StreamProp2,Namespace.AlwaysBindableAction1))"; this.GetWriterOutputForContentTypeAndKnobValue("application/json;odata.metadata=full", true, itemsToWrite, edmModel: Model, edmEntitySet: null, edmEntityType: EntityType, selectClause: selectClause, expandClause: expandClause) .Should().Be(expectedPayload); }
public void ShouldWritePayloadWhenExpandedFeedAndEntryHasSerializationInfo() { List<ODataItem> itemsToWrite = new List<ODataItem>(); var entry1 = new ODataEntry(); entry1.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "MySet", NavigationSourceEntityTypeName = "NS.MyEntityType" }); itemsToWrite.Add(entry1); itemsToWrite.Add(new ODataNavigationLink { Name = "EntitySetReferenceProperty", IsCollection = true }); var feed = new ODataFeed(); feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "MySet", NavigationSourceEntityTypeName = "NS.MyEntityType" }); itemsToWrite.Add(feed); var entry2 = new ODataEntry(); entry2.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "MySet2", NavigationSourceEntityTypeName = "NS.MyEntityType2" }); itemsToWrite.Add(entry2); const string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#MySet/$entity\",\"EntitySetReferenceProperty\":[{}]}"; this.WriteNestedItemsAndValidatePayload(entitySetFullName: null, derivedEntityTypeFullName: null, nestedItemToWrite: itemsToWrite.ToArray(), expectedPayload: expectedPayload, writingResponse: true); }
private void WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext) { Contract.Assert(writer != null); Contract.Assert(writeContext != null); Contract.Assert(enumerable != null); Contract.Assert(feedType != null); IEdmEntityTypeReference elementType = GetEntityType(feedType); ODataFeed feed = CreateODataFeed(enumerable, feedType.AsCollection(), writeContext); if (feed == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, Feed)); } IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase; if (entitySet == null) { feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { IsFromCollection = true, NavigationSourceEntityTypeName = elementType.FullName(), NavigationSourceKind = EdmNavigationSourceKind.UnknownEntitySet, NavigationSourceName = null }); } ODataEdmTypeSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType); if (entrySerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } // save this for later to support JSON odata.streaming. Uri nextPageLink = feed.NextPageLink; feed.NextPageLink = null; writer.WriteStart(feed); foreach (object entry in enumerable) { if (entry == null) { throw new SerializationException(SRResources.NullElementInCollection); } entrySerializer.WriteObjectInline(entry, elementType, writer, writeContext); } // Subtle and suprising behavior: If the NextPageLink property is set before calling WriteStart(feed), // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if // the next page link is not set when calling WriteStart(feed) but is instead set later on that feed // object before calling WriteEnd(), the next page link will be written at the end, as required for // odata.streaming=true support. if (nextPageLink != null) { feed.NextPageLink = nextPageLink; } writer.WriteEnd(); }
private string WriteAndVerifyEmployeeFeed(ODataMessageWriterSettings settings, string mimeType, bool hasModel) { // create a feed with two entries var employeeFeed = new ODataFeed(); if (mimeType == MimeTypes.ApplicationAtomXml) { employeeFeed.Id = new Uri(this.ServiceUri + "Person/" + NameSpace + "Employee"); } if (!hasModel) { employeeFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Person", NavigationSourceEntityTypeName = NameSpace + "Person", ExpectedTypeName = NameSpace + "Employee" }); } ODataEntry employeeEntry = WritePayloadHelper.CreateEmployeeEntryNoMetadata(false); ODataEntry specialEmployeeEntry = WritePayloadHelper.CreateSpecialEmployeeEntryNoMetadata(false); // expected result with AutoGeneratedUrlsShouldPutKeyValueInDedicatedSegment Dictionary <string, object> expectedEmployeeObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.EmployeeType, "Person/-3", employeeEntry, hasModel, true); Dictionary <string, object> expectedSpecialEmployeeObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.SpecialEmployeeType, "Person/-10", specialEmployeeEntry, hasModel, true); // write the response message and read using ODL reader var responseMessage = new StreamResponseMessage(new MemoryStream()); responseMessage.SetHeader("Content-Type", mimeType); string result = string.Empty; using (var messageWriter = this.CreateODataMessageWriter(responseMessage, settings, hasModel)) { var odataWriter = this.CreateODataFeedWriter(messageWriter, WritePayloadHelper.PersonSet, WritePayloadHelper.EmployeeType, hasModel); odataWriter.WriteStart(employeeFeed); odataWriter.WriteStart(employeeEntry); odataWriter.WriteEnd(); // toggle AutoComputePayloadMetadataInJson, this should not affect the writing result settings.AutoComputePayloadMetadataInJson = !settings.AutoComputePayloadMetadataInJson; odataWriter.WriteStart(specialEmployeeEntry); odataWriter.WriteEnd(); odataWriter.WriteEnd(); result = this.ReadFeedEntryMessage(true, responseMessage, mimeType, WritePayloadHelper.PersonSet, WritePayloadHelper.PersonType); } // For Json light, verify the resulting metadata is as expected if (mimeType != MimeTypes.ApplicationAtomXml) { JavaScriptSerializer jScriptSerializer = new JavaScriptSerializer(); Dictionary <string, object> resultObject = jScriptSerializer.DeserializeObject(result) as Dictionary <string, object>; VerifyODataContextAnnotation(this.ServiceUri + "$metadata#Person/" + NameSpace + "Employee", resultObject, mimeType); settings.AutoComputePayloadMetadataInJson = !settings.AutoComputePayloadMetadataInJson; VerifyEntry(expectedEmployeeObject, employeeEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).First() as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); VerifyEntry(expectedSpecialEmployeeObject, specialEmployeeEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).Last() as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); } return(result); }
private string WriteAndVerifyPersonFeed(ODataMessageWriterSettings settings, string mimeType, bool hasModel) { // create a Person feed containing a person, an employee, a special employee var personFeed = new ODataFeed(); if (mimeType == MimeTypes.ApplicationAtomXml) { personFeed.Id = new Uri(this.ServiceUri + "Person"); } if (!hasModel) { personFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Person", NavigationSourceEntityTypeName = NameSpace + "Person" }); } ODataEntry personEntry = WritePayloadHelper.CreatePersonEntryNoMetadata(hasModel); Dictionary <string, object> expectedPersonObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.PersonType, "Person(-5)", personEntry, hasModel); ODataEntry employeeEntry = WritePayloadHelper.CreateEmployeeEntryNoMetadata(hasModel); Dictionary <string, object> expectedEmployeeObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.EmployeeType, "Person(-3)", employeeEntry, hasModel, true); ODataEntry specialEmployeeEntry = WritePayloadHelper.CreateSpecialEmployeeEntryNoMetadata(hasModel); Dictionary <string, object> expectedSpecialEmployeeObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.SpecialEmployeeType, "Person(-10)", specialEmployeeEntry, hasModel, true); // write the response message and read using ODL reader var responseMessage = new StreamResponseMessage(new MemoryStream()); responseMessage.SetHeader("Content-Type", mimeType); string result = string.Empty; using (var messageWriter = this.CreateODataMessageWriter(responseMessage, settings, hasModel)) { var odataWriter = this.CreateODataFeedWriter(messageWriter, WritePayloadHelper.PersonSet, WritePayloadHelper.PersonType, hasModel); odataWriter.WriteStart(personFeed); odataWriter.WriteStart(personEntry); odataWriter.WriteEnd(); odataWriter.WriteStart(employeeEntry); odataWriter.WriteEnd(); odataWriter.WriteStart(specialEmployeeEntry); odataWriter.WriteEnd(); // Finish writing the feed. odataWriter.WriteEnd(); result = this.ReadFeedEntryMessage(true, responseMessage, mimeType, WritePayloadHelper.PersonSet, WritePayloadHelper.PersonType); } // For Json light, verify the resulting metadata is as expected if (mimeType != MimeTypes.ApplicationAtomXml) { JavaScriptSerializer jScriptSerializer = new JavaScriptSerializer(); Dictionary <string, object> resultObject = jScriptSerializer.DeserializeObject(result) as Dictionary <string, object>; VerifyODataContextAnnotation(this.ServiceUri + "$metadata#Person", resultObject, mimeType); VerifyEntry(expectedPersonObject, personEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).ElementAt(0) as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); VerifyEntry(expectedEmployeeObject, employeeEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).ElementAt(1) as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); VerifyEntry(expectedSpecialEmployeeObject, specialEmployeeEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).ElementAt(2) as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); } return(result); }
private string WriteAndVerifyExpandedCustomerEntry(ODataMessageWriterSettings settings, string mimeType, string expectedProjectionClause, bool hasModel) { ODataEntry customerEntry = WritePayloadHelper.CreateCustomerEntryNoMetadata(hasModel); Dictionary <string, object> expectedCustomerObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.CustomerType, "Customer(-9)", customerEntry, hasModel); var thumbnailProperty = WritePayloadHelper.AddCustomerMediaProperty(customerEntry, expectedCustomerObject); // order navigation var orderNavigation = WritePayloadHelper.CreateCustomerOrderNavigation(expectedCustomerObject); // expanded logins navigation containing a Login instance var expandedLoginsNavigation = WritePayloadHelper.CreateExpandedCustomerLoginsNavigation(expectedCustomerObject); var loginFeed = new ODataFeed(); if (mimeType == MimeTypes.ApplicationAtomXml) { loginFeed.Id = new Uri(this.ServiceUri + "Customer(-9)/Logins"); } if (!hasModel) { loginFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Login", NavigationSourceEntityTypeName = NameSpace + "Login" }); } var loginEntry = WritePayloadHelper.CreateLoginEntryNoMetadata(hasModel); Dictionary <string, object> expectedLoginObject = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.LoginType, "Login('2')", loginEntry, hasModel); this.RemoveNonSelectedMetadataFromExpected(expectedCustomerObject, expectedLoginObject, hasModel); // write the response message and read using ODL reader var responseMessage = new StreamResponseMessage(new MemoryStream()); responseMessage.SetHeader("Content-Type", mimeType); string result = string.Empty; using (var messageWriter = this.CreateODataMessageWriter(responseMessage, settings, hasModel)) { var odataWriter = this.CreateODataEntryWriter(messageWriter, WritePayloadHelper.CustomerSet, WritePayloadHelper.CustomerType, hasModel); odataWriter.WriteStart(customerEntry); odataWriter.WriteStart(orderNavigation); odataWriter.WriteEnd(); // write expanded navigation odataWriter.WriteStart(expandedLoginsNavigation); odataWriter.WriteStart(loginFeed); odataWriter.WriteStart(loginEntry); odataWriter.WriteEnd(); odataWriter.WriteEnd(); // Finish writing expandedNavigation. odataWriter.WriteEnd(); // Finish writing customerEntry. odataWriter.WriteEnd(); result = this.ReadFeedEntryMessage(false, responseMessage, mimeType, WritePayloadHelper.CustomerSet, WritePayloadHelper.CustomerType); } // For Json light, verify the resulting metadata is as expected if (mimeType != MimeTypes.ApplicationAtomXml) { JavaScriptSerializer jScriptSerializer = new JavaScriptSerializer(); Dictionary <string, object> resultObject = jScriptSerializer.DeserializeObject(result) as Dictionary <string, object>; VerifyODataContextAnnotation(this.ServiceUri + "$metadata#Customer(" + expectedProjectionClause + ")/$entity", resultObject, mimeType); VerifyEntry(expectedCustomerObject, customerEntry, new ODataNavigationLink[] { orderNavigation, expandedLoginsNavigation }, new ODataProperty[] { thumbnailProperty }, resultObject, mimeType, settings.AutoComputePayloadMetadataInJson); VerifyEntry(expectedLoginObject, loginEntry, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject["Logins"] as object[]).Single() as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); } return(result); }
private string WriteAndVerifyExpandedCustomerEntry(StreamResponseMessage responseMessage, ODataWriter odataWriter, bool hasModel, string mimeType) { ODataEntry customerEntry = WritePayloadHelper.CreateCustomerEntry(hasModel); odataWriter.WriteStart(customerEntry); // write non-expanded navigations foreach (var navigation in WritePayloadHelper.CreateCustomerNavigationLinks()) { odataWriter.WriteStart(navigation); odataWriter.WriteEnd(); } // write expanded navigation var expandedNavigation = new ODataNavigationLink() { Name = "Logins", IsCollection = true, Url = new Uri(this.ServiceUri + "Customer(-9)/Logins") }; odataWriter.WriteStart(expandedNavigation); var loginFeed = new ODataFeed() { Id = new Uri(this.ServiceUri + "Customer(-9)/Logins") }; if (!hasModel) { loginFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Login", NavigationSourceEntityTypeName = NameSpace + "Login" }); } odataWriter.WriteStart(loginFeed); var loginEntry = WritePayloadHelper.CreateLoginEntry(hasModel); odataWriter.WriteStart(loginEntry); foreach (var navigation in WritePayloadHelper.CreateLoginNavigationLinks()) { odataWriter.WriteStart(navigation); odataWriter.WriteEnd(); } // Finish writing loginEntry. odataWriter.WriteEnd(); // Finish writing the loginFeed. odataWriter.WriteEnd(); // Finish writing expandedNavigation. odataWriter.WriteEnd(); // Finish writing customerEntry. odataWriter.WriteEnd(); // Some very basic verification for the payload. bool verifyFeedCalled = false; int verifyEntryCalled = 0; bool verifyNavigationCalled = false; Action <ODataFeed> verifyFeed = (feed) => { verifyFeedCalled = true; }; Action <ODataEntry> verifyEntry = (entry) => { if (entry.TypeName.Contains("Customer")) { Assert.AreEqual(7, entry.Properties.Count()); } if (entry.TypeName.Contains("Login")) { Assert.AreEqual(2, entry.Properties.Count()); } verifyEntryCalled++; }; Action <ODataNavigationLink> verifyNavigation = (navigation) => { Assert.IsNotNull(navigation.Name); verifyNavigationCalled = true; }; Stream stream = responseMessage.GetStream(); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { stream.Seek(0, SeekOrigin.Begin); WritePayloadHelper.ReadAndVerifyFeedEntryMessage(false, responseMessage, WritePayloadHelper.CustomerSet, WritePayloadHelper.CustomerType, verifyFeed, verifyEntry, verifyNavigation); Assert.IsTrue(verifyFeedCalled && verifyEntryCalled == 2 && verifyNavigationCalled, "Verification action not called."); } return(WritePayloadHelper.ReadStreamContent(stream)); }
private string WriteAndVerifyOrderFeed(ODataMessageWriterSettings settings, string mimeType, bool hasModel) { // create a feed with two entries var orderFeed = new ODataFeed() { NextPageLink = new Uri(this.ServiceUri + "Order?$skiptoken=-9"), Count = 9999 }; if (mimeType == MimeTypes.ApplicationAtomXml) { orderFeed.Id = new Uri(this.ServiceUri + "Order"); } if (!hasModel) { orderFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Order", NavigationSourceEntityTypeName = NameSpace + "Order" }); } var orderEntry1 = WritePayloadHelper.CreateOrderEntry1NoMetadata(hasModel); Dictionary <string, object> expectedOrderObject1 = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.OrderType, "Order(-10)", orderEntry1, hasModel); var orderEntry2 = WritePayloadHelper.CreateOrderEntry2NoMetadata(hasModel); Dictionary <string, object> expectedOrderObject2 = WritePayloadHelper.ComputeExpectedFullMetadataEntryObject(WritePayloadHelper.OrderType, "Order(-9)", orderEntry2, hasModel); var orderEntry2Navigation = WritePayloadHelper.AddOrderEntryCustomNavigation(orderEntry2, expectedOrderObject2, hasModel); // write the response message and read using ODL reader var responseMessage = new StreamResponseMessage(new MemoryStream()); responseMessage.SetHeader("Content-Type", mimeType); string result = string.Empty; using (var messageWriter = this.CreateODataMessageWriter(responseMessage, settings, hasModel)) { var odataWriter = this.CreateODataFeedWriter(messageWriter, WritePayloadHelper.OrderSet, WritePayloadHelper.OrderType, hasModel); odataWriter.WriteStart(orderFeed); odataWriter.WriteStart(orderEntry1); odataWriter.WriteEnd(); odataWriter.WriteStart(orderEntry2); odataWriter.WriteStart(orderEntry2Navigation); odataWriter.WriteEnd(); odataWriter.WriteEnd(); // Finish writing the feed. odataWriter.WriteEnd(); result = this.ReadFeedEntryMessage(true, responseMessage, mimeType, WritePayloadHelper.OrderSet, WritePayloadHelper.OrderType); } if (mimeType != MimeTypes.ApplicationAtomXml) { JavaScriptSerializer jScriptSerializer = new JavaScriptSerializer(); Dictionary <string, object> resultObject = jScriptSerializer.DeserializeObject(result) as Dictionary <string, object>; Assert.AreEqual(this.ServiceUri + "Order?$skiptoken=-9", resultObject.Single(e => e.Key == (JsonLightConstants.ODataNextLinkAnnotationName)).Value, "Feed next link"); Assert.AreEqual(9999, resultObject.Single(e => e.Key == (JsonLightConstants.ODataCountAnnotationName)).Value, "Feed count"); resultObject.Remove(JsonLightConstants.ODataNextLinkAnnotationName); resultObject.Remove(JsonLightConstants.ODataCountAnnotationName); VerifyODataContextAnnotation(this.ServiceUri + "$metadata#Order", resultObject, mimeType); VerifyEntry(expectedOrderObject1, orderEntry1, new ODataNavigationLink[] { }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).First() as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); VerifyEntry(expectedOrderObject2, orderEntry2, new ODataNavigationLink[] { orderEntry2Navigation }, new ODataProperty[] { }, (resultObject.Last().Value as object[]).Last() as Dictionary <string, object>, mimeType, settings.AutoComputePayloadMetadataInJson); } return(result); }
private string WriteAndVerifyPersonFeed(StreamResponseMessage responseMessage, ODataWriter odataWriter, bool hasModel, string mimeType) { var personFeed = new ODataFeed() { Id = new Uri(this.ServiceUri + "Person"), DeltaLink = new Uri(this.ServiceUri + "Person") }; if (!hasModel) { personFeed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Person", NavigationSourceEntityTypeName = NameSpace + "Person" }); } odataWriter.WriteStart(personFeed); ODataEntry personEntry = WritePayloadHelper.CreatePersonEntry(hasModel); odataWriter.WriteStart(personEntry); var personNavigation = new ODataNavigationLink() { Name = "PersonMetadata", IsCollection = true, Url = new Uri("Person(-5)/PersonMetadata", UriKind.Relative) }; odataWriter.WriteStart(personNavigation); odataWriter.WriteEnd(); // Finish writing personEntry. odataWriter.WriteEnd(); ODataEntry employeeEntry = WritePayloadHelper.CreateEmployeeEntry(hasModel); odataWriter.WriteStart(employeeEntry); var employeeNavigation1 = new ODataNavigationLink() { Name = "PersonMetadata", IsCollection = true, Url = new Uri("Person(-3)/" + NameSpace + "Employee" + "/PersonMetadata", UriKind.Relative) }; odataWriter.WriteStart(employeeNavigation1); odataWriter.WriteEnd(); var employeeNavigation2 = new ODataNavigationLink() { Name = "Manager", IsCollection = false, Url = new Uri("Person(-3)/" + NameSpace + "Employee" + "/Manager", UriKind.Relative) }; odataWriter.WriteStart(employeeNavigation2); odataWriter.WriteEnd(); // Finish writing employeeEntry. odataWriter.WriteEnd(); ODataEntry specialEmployeeEntry = WritePayloadHelper.CreateSpecialEmployeeEntry(hasModel); odataWriter.WriteStart(specialEmployeeEntry); var specialEmployeeNavigation1 = new ODataNavigationLink() { Name = "PersonMetadata", IsCollection = true, Url = new Uri("Person(-10)/" + NameSpace + "SpecialEmployee" + "/PersonMetadata", UriKind.Relative) }; odataWriter.WriteStart(specialEmployeeNavigation1); odataWriter.WriteEnd(); var specialEmployeeNavigation2 = new ODataNavigationLink() { Name = "Manager", IsCollection = false, Url = new Uri("Person(-10)/" + NameSpace + "SpecialEmployee" + "/Manager", UriKind.Relative) }; odataWriter.WriteStart(specialEmployeeNavigation2); odataWriter.WriteEnd(); var specialEmployeeNavigation3 = new ODataNavigationLink() { Name = "Car", IsCollection = false, Url = new Uri("Person(-10)/" + NameSpace + "SpecialEmployee" + "/Manager", UriKind.Relative) }; odataWriter.WriteStart(specialEmployeeNavigation3); odataWriter.WriteEnd(); // Finish writing specialEmployeeEntry. odataWriter.WriteEnd(); // Finish writing the feed. odataWriter.WriteEnd(); // Some very basic verification for the payload. bool verifyFeedCalled = false; bool verifyEntryCalled = false; bool verifyNavigationCalled = false; Action <ODataFeed> verifyFeed = (feed) => { if (mimeType != MimeTypes.ApplicationAtomXml) { Assert.IsTrue(feed.DeltaLink.AbsoluteUri.Contains("Person")); } verifyFeedCalled = true; }; Action <ODataEntry> verifyEntry = (entry) => { Assert.IsTrue(entry.EditLink.AbsoluteUri.EndsWith("Person(-5)") || entry.EditLink.AbsoluteUri.EndsWith("Person(-3)/" + NameSpace + "Employee") || entry.EditLink.AbsoluteUri.EndsWith("Person(-10)/" + NameSpace + "SpecialEmployee")); verifyEntryCalled = true; }; Action <ODataNavigationLink> verifyNavigation = (navigation) => { Assert.IsTrue(navigation.Name == "PersonMetadata" || navigation.Name == "Manager" || navigation.Name == "Car"); verifyNavigationCalled = true; }; Stream stream = responseMessage.GetStream(); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { stream.Seek(0, SeekOrigin.Begin); WritePayloadHelper.ReadAndVerifyFeedEntryMessage(true, responseMessage, WritePayloadHelper.PersonSet, WritePayloadHelper.PersonType, verifyFeed, verifyEntry, verifyNavigation); Assert.IsTrue(verifyFeedCalled && verifyEntryCalled && verifyNavigationCalled, "Verification action not called."); } return(WritePayloadHelper.ReadStreamContent(stream)); }
public static void FeedWriteReadNormal() { ODataFeed Feed = new ODataFeed(); Feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Mails", NavigationSourceEntityTypeName = "NS.Mail", NavigationSourceKind = EdmNavigationSourceKind.ContainedEntitySet }); ODataEntry Entry = new ODataEntry() { Properties = new[] { new ODataProperty() { Name = "Id", Value = 2 }, }, EditLink = new Uri("http://example/Web/Users(3)"), }; Entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "MyLogin", NavigationSourceEntityTypeName = "NS.Person", NavigationSourceKind = EdmNavigationSourceKind.ContainedEntitySet }); // Parse the full request Uri ODataPath path = new ODataUriParser( CraftModel.Model, new Uri("http://example.org/svc/"), new Uri("http://example.org/svc/MyLogin/Mails")).ParsePath(); // Alternatively, construct the normal path for the contained entity manually. //ODataPath path = new ODataPath( // new ODataPathSegment[] // { // new SingletonSegment(CraftModel.MyLogin), new NavigationPropertySegment(CraftModel.MailBox, CraftModel.MyLogin) // }); var stream = new MemoryStream(); var wsetting = new ODataMessageWriterSettings() { DisableMessageStreamDisposal = true, ODataUri = new ODataUri() { ServiceRoot = new Uri("http://example.org/svc/"), Path = path } }; IODataResponseMessage msg = new Message() { Stream = stream, }; var omw = new ODataMessageWriter(msg, wsetting); var writer = omw.CreateODataFeedWriter(); writer.WriteStart(Feed); writer.WriteStart(Entry); writer.WriteEnd(); writer.WriteEnd(); stream.Seek(0, SeekOrigin.Begin); var payload = new StreamReader(stream).ReadToEnd(); // {"@odata.context":"http://example.org/svc/$metadata#Web/Items","value":[{"@odata.editLink":"http://example/Web/Users(3)","Id":2}]} Console.WriteLine(payload); //Read ODataEntry entry = null; stream.Seek(0, SeekOrigin.Begin); var rsetting = new ODataMessageReaderSettings(); var omr = new ODataMessageReader(msg, rsetting, CraftModel.Model); var reader = omr.CreateODataFeedReader(); while (reader.Read()) { if (reader.State == ODataReaderState.EntryEnd) { entry = (ODataEntry)reader.Item; break; } } //Id=2 foreach (var prop in entry.Properties) { Console.WriteLine("{0}={1}", prop.Name, prop.Value); } }
/// <summary> /// Writes the feed element for the atom payload. /// </summary> /// <param name="expanded">Expanded properties for the result.</param> /// <param name="elements">Collection of entries in the feed element.</param> /// <param name="expectedType">ExpectedType of the elements in the collection.</param> /// <param name="title">Title of the feed element.</param> /// <param name="getRelativeUri">Callback to get the relative uri of the feed.</param> /// <param name="getAbsoluteUri">Callback to get the absolute uri of the feed.</param> /// <param name="topLevel">True if the feed is the top level feed, otherwise false for the inner expanded feed.</param> private void WriteFeedElements( IExpandedResult expanded, QueryResultInfo elements, ResourceType expectedType, string title, Func <Uri> getRelativeUri, Func <Uri> getAbsoluteUri, bool topLevel) { Debug.Assert(elements != null, "elements != null"); Debug.Assert(expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType, "expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType"); Debug.Assert(!string.IsNullOrEmpty(title), "!string.IsNullOrEmpty(title)"); ODataFeed feed = new ODataFeed(); feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = this.CurrentContainer.Name, NavigationSourceEntityTypeName = this.CurrentContainer.ResourceType.FullName, ExpectedTypeName = expectedType.FullName }); // Write the other elements for the feed this.PayloadMetadataPropertyManager.SetId(feed, () => getAbsoluteUri()); #pragma warning disable 618 if (this.contentFormat == ODataFormat.Atom) #pragma warning restore 618 { // Create the atom feed metadata and set the self link and title value. AtomFeedMetadata feedMetadata = new AtomFeedMetadata(); feed.SetAnnotation(feedMetadata); feedMetadata.Title = new AtomTextConstruct { Text = title }; feedMetadata.SelfLink = new AtomLinkMetadata { Href = getRelativeUri(), Title = title }; } // support for $count // in ATOM we write it at the beginning (we always have) // in JSON for backward compatiblity reasons we write it at the end, so we must not fill it here. if (topLevel && this.RequestDescription.CountOption == RequestQueryCountOption.CountQuery) { feed.Count = this.RequestDescription.CountValue; } var feedArgs = elements.GetDataServiceODataWriterFeedArgs(feed, this.Service.OperationContext); this.dataServicesODataWriter.WriteStart(feedArgs); object lastObject = null; IExpandedResult lastExpandedSkipToken = null; while (elements.HasMoved) { object o = elements.Current; IExpandedResult skipToken = this.GetSkipToken(expanded); if (o != null) { IExpandedResult expandedO = o as IExpandedResult; if (expandedO != null) { expanded = expandedO; o = GetExpandedElement(expanded); skipToken = this.GetSkipToken(expanded); } this.WriteEntry(expanded, o, true /*resourceInstanceInFeed*/, expectedType); } elements.MoveNext(); lastObject = o; lastExpandedSkipToken = skipToken; } // After looping through the objects in the sequence, decide if we need to write the next // page link and if yes, write it by invoking the delegate if (this.NeedNextPageLink(elements)) { this.PayloadMetadataPropertyManager.SetNextPageLink( feed, this.AbsoluteServiceUri, this.GetNextLinkUri(lastObject, lastExpandedSkipToken, getAbsoluteUri())); } this.dataServicesODataWriter.WriteEnd(feedArgs); #if ASTORIA_FF_CALLBACKS this.Service.InternalOnWriteFeed(feed); #endif }
public void ShouldWritePayloadWhenFeedAndEntryHasSerializationInfo() { var feed = new ODataFeed(); feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "MySet", NavigationSourceEntityTypeName = "NS.MyEntityType" }); var entry = new ODataEntry(); entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "MySet2", NavigationSourceEntityTypeName = "NS.MyEntityType2" }); List<ODataItem> itemsToWrite = new List<ODataItem>() { feed, entry }; const string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#MySet\",\"value\":[{}]}"; this.WriteNestedItemsAndValidatePayload(entitySetFullName: null, derivedEntityTypeFullName: null, nestedItemToWrite: itemsToWrite.ToArray(), expectedPayload: expectedPayload, writingResponse: true); }