public void SetFeedSerializationInfoShouldThrowOnNullFeed()
        {
            ODataResourceSet resourceCollection = null;
            Action           action             = () => resourceCollection.SetSerializationInfo(null);

            Assert.Throws <ArgumentNullException>("resourceSet", action);
        }
Example #2
0
        private ODataResourceSet GetResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, IEdmStructuredTypeReference elementType,
                                                ODataSerializerContext writeContext)
        {
            ODataResourceSet resourceSet = CreateResourceSet(enumerable, resourceSetType.AsCollection(), writeContext);

            if (resourceSet == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, ResourceSet));
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;

            if (entitySet == null)
            {
                resourceSet.SetSerializationInfo(new ODataResourceSerializationInfo
                {
                    IsFromCollection = true,
                    NavigationSourceEntityTypeName = elementType.FullName(),
                    NavigationSourceKind           = EdmNavigationSourceKind.UnknownEntitySet,
                    NavigationSourceName           = null
                });
            }

            return(resourceSet);
        }
        public void SetFeedSerializationInfoShouldThrowOnNullFeed()
        {
            ODataResourceSet resourceCollection = null;
            Action           action             = () => resourceCollection.SetSerializationInfo(null);

            action.ShouldThrow <ArgumentNullException>().Where(e => e.Message.Contains("resourceSet"));
        }
Example #4
0
        /// <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, IEdmStructuredType entityType, IEnumerable entries, IEdmEntitySetBase entitySet, ODataVersion targetVersion, SelectExpandClause selectExpandClause, long?count, Uri deltaLink, Uri nextPageLink, Dictionary <string, string> incomingHeaders = null)
        {
            var feed = new ODataResourceSet
            {
                Id           = entitySet == null ? null : new Uri(ServiceConstants.ServiceBaseUri, entitySet.Name),
                DeltaLink    = deltaLink,
                NextPageLink = nextPageLink
            };

            if (entitySet == null)
            {
                feed.SetSerializationInfo(new ODataResourceSerializationInfo()
                {
                    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 ShouldWriteContextUriBasedOnSerializationInfoForComplexCollectionResponseWithoutUserModelWhenBothItemTypeAndSerializationInfoAreGiven_Inherit()
        {
            ODataResourceSet collectionStart = new ODataResourceSet();

            collectionStart.SetSerializationInfo(new ODataResourceSerializationInfo {
                ExpectedTypeName = "foo.bar"
            });
            WriteAndValidate(collectionStart, this.derivedItems, "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection(foo.bar)\",\"value\":[{\"@odata.type\":\"#ns.DerivedAddress\",\"Street\":\"1 Microsoft Way\",\"Zipcode\":98052,\"State\":\"WA\",\"City\":\"Shanghai\"}]}", writingResponse: true, itemTypeReference: this.derivedAddressTypeReference);
        }
        public void ShouldBeAbleToSetTheFeedSerializationInfo()
        {
            ODataResourceSet resourceCollection = new ODataResourceSet();
            ODataResourceSerializationInfo serializationInfo = new ODataResourceSerializationInfo {
                NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.base", ExpectedTypeName = "ns.expected"
            };

            resourceCollection.SetSerializationInfo(serializationInfo);
            Assert.Same(serializationInfo, resourceCollection.SerializationInfo);
        }
        public void ShouldBeAbleToClearTheFeedSerializationInfo()
        {
            ODataResourceSet resourceCollection = new ODataResourceSet();
            ODataResourceSerializationInfo serializationInfo = new ODataResourceSerializationInfo {
                NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.base", ExpectedTypeName = "ns.expected"
            };

            resourceCollection.SerializationInfo = serializationInfo;
            resourceCollection.SetSerializationInfo(null);
            resourceCollection.SerializationInfo.Should().BeNull();
        }
        public void ShouldWriteCountAndNextLinkAnnotationOfComplexCollectionPropertyIfSpecified()
        {
            ODataResourceSet collectionStart = new ODataResourceSet()
            {
                Count        = 3,
                NextPageLink = new Uri("http://next-link")
            };

            collectionStart.SetSerializationInfo(new ODataResourceSerializationInfo {
                ExpectedTypeName = "foo.bar"
            });
            WriteAndValidate(collectionStart, this.items, "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection(foo.bar)\",\"@odata.count\":3,\"@odata.nextLink\":\"http://next-link/\",\"value\":[{\"Street\":\"1 Microsoft Way\",\"Zipcode\":98052,\"State\":\"WA\"}]}", writingResponse: true, itemTypeReference: this.addressTypeReference);
        }
Example #9
0
        private async Task WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer,
                                            ODataSerializerContext writeContext)
        {
            Contract.Assert(writer != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(enumerable != null);
            Contract.Assert(resourceSetType != null);

            IEdmStructuredTypeReference elementType = GetResourceType(resourceSetType);
            ODataResourceSet            resourceSet = CreateResourceSet(enumerable, resourceSetType.AsCollection(), writeContext);

            if (resourceSet == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, ResourceSet));
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;

            if (entitySet == null)
            {
                resourceSet.SetSerializationInfo(new ODataResourceSerializationInfo
                {
                    IsFromCollection = true,
                    NavigationSourceEntityTypeName = elementType.FullName(),
                    NavigationSourceKind           = EdmNavigationSourceKind.UnknownEntitySet,
                    NavigationSourceName           = null
                });
            }

            ODataEdmTypeSerializer resourceSerializer = SerializerProvider.GetEdmTypeSerializer(writeContext.Context, elementType);

            if (resourceSerializer == null)
            {
                throw new SerializationException(
                          Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataOutputFormatter).Name));
            }

            // save this for later to support JSON odata.streaming.
            Uri nextPageLink = resourceSet.NextPageLink;

            resourceSet.CountOnly    = enumerable is ICountOptionCollection && (enumerable as ITruncatedCollection).OnlyCount;
            resourceSet.NextPageLink = null;

            writer.WriteStart(resourceSet);

            foreach (object item in enumerable)
            {
                if (item == null || item is NullEdmComplexObject)
                {
                    if (elementType.IsEntity())
                    {
                        throw new SerializationException(SRResources.NullElementInCollection);
                    }

                    // for null complex element, it can be serialized as "null" in the collection.
                    writer.WriteStart(resource: null);
                    writer.WriteEnd();
                }
                else
                {
                    await resourceSerializer.WriteObjectInlineAsync(item, elementType, writer, writeContext);
                }
            }

            // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(resourceSet),
            // 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(resourceSet) but is instead set later on that resourceSet
            // object before calling WriteEnd(), the next page link will be written at the end, as required for
            // odata.streaming=true support.

            if (nextPageLink != null)
            {
                resourceSet.NextPageLink = nextPageLink;
            }

            writer.WriteEnd();
        }
        public ODataJsonLightInheritComplexCollectionWriterTests()
        {
            collectionStartWithoutSerializationInfo = new ODataResourceSet();

            collectionStartWithSerializationInfo = new ODataResourceSet();
            collectionStartWithSerializationInfo.SetSerializationInfo(new ODataResourceSerializationInfo {
                ExpectedTypeName = "ns.Address"
            });

            address = new ODataResource
            {
                Properties = new[]
                {
                    new ODataProperty {
                        Name = "Street", Value = "1 Microsoft Way"
                    },
                    new ODataProperty {
                        Name = "Zipcode", Value = 98052
                    },
                    new ODataProperty {
                        Name = "State", Value = new ODataEnumValue("WA", "ns.StateEnum")
                    }
                }
            };
            items = new[] { address };

            derivedAddress = new ODataResource
            {
                Properties = new[]
                {
                    new ODataProperty {
                        Name = "Street", Value = "1 Microsoft Way"
                    },
                    new ODataProperty {
                        Name = "Zipcode", Value = 98052
                    },
                    new ODataProperty {
                        Name = "State", Value = new ODataEnumValue("WA", "ns.StateEnum")
                    },
                    new ODataProperty {
                        Name = "City", Value = "Shanghai"
                    }
                },
                TypeName = "ns.DerivedAddress"
            };

            derivedItems = new[] { derivedAddress };

            EdmComplexType addressType = new EdmComplexType("ns", "Address");

            addressType.AddProperty(new EdmStructuralProperty(addressType, "Street", EdmCoreModel.Instance.GetString(isNullable: true)));
            addressType.AddProperty(new EdmStructuralProperty(addressType, "Zipcode", EdmCoreModel.Instance.GetInt32(isNullable: true)));
            var stateEnumType = new EdmEnumType("ns", "StateEnum", isFlags: true);

            stateEnumType.AddMember("IL", new EdmEnumMemberValue(1));
            stateEnumType.AddMember("WA", new EdmEnumMemberValue(2));
            addressType.AddProperty(new EdmStructuralProperty(addressType, "State", new EdmEnumTypeReference(stateEnumType, true)));

            EdmComplexType derivedAddressType = new EdmComplexType("ns", "DerivedAddress", addressType, false);

            derivedAddressType.AddProperty(new EdmStructuralProperty(derivedAddressType, "City", EdmCoreModel.Instance.GetString(isNullable: true)));

            addressTypeReference        = new EdmComplexTypeReference(addressType, isNullable: false);
            derivedAddressTypeReference = new EdmComplexTypeReference(derivedAddressType, isNullable: false);
        }
        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 {
                EnableMessageStreamDisposal = false
            };

            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.CreateODataResourceSetWriter();

                // Create customers feed with serializtion info to write odata.metadata.
                var customersFeed = new ODataResourceSet();
                customersFeed.SetSerializationInfo(new ODataResourceSerializationInfo {
                    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 ODataResource {
                        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 ODataResource should be sufficient for the 5.5 release.
                        var navigationLink = new ODataNestedResourceInfo {
                            Name = "MostRecentOrder", IsCollection = false, Url = new Uri("MostRecentOrder", UriKind.Relative)
                        };
                        odataWriter.WriteStart(navigationLink);

                        // Write the most recent customer.
                        {
                            var mostRecentOrder = new ODataResource {
                                TypeName = "NS.Order"
                            };

                            // Add serialization info so we can computer links.
                            mostRecentOrder.SetSerializationInfo(new ODataResourceSerializationInfo {
                                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);
        }
Example #12
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)");

            ODataResourceSet feed = new ODataResourceSet();

            feed.SetSerializationInfo(new ODataResourceSerializationInfo {
                NavigationSourceName = this.CurrentContainer.Name, NavigationSourceEntityTypeName = this.CurrentContainer.ResourceType.FullName, ExpectedTypeName = expectedType.FullName
            });

            // Write the other elements for the feed
            this.PayloadMetadataPropertyManager.SetId(feed, () => getAbsoluteUri());

            // 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
        }