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 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 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);
        }
        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 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 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 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;
        }
        /// <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 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 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);
 }
 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);
 }
示例#12
0
        public static void FeedWriteReadNormal()
        {
            Console.WriteLine("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);
            }
        }
示例#13
0
        /// <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
        }
        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);
        }
        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(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);
        }