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 WriteStartShouldIgnoreDeltaLinkWhenWritingResponseTopLevelFeed() { string expectedPayload = @"<?xml version=""1.0"" encoding=""utf-8""?>" + @"<feed xmlns=""http://www.w3.org/2005/Atom"" xmlns:d=""http://docs.oasis-open.org/odata/ns/data"" xmlns:m=""http://docs.oasis-open.org/odata/ns/metadata"" xmlns:georss=""http://www.georss.org/georss"" xmlns:gml=""http://www.opengis.net/gml"" m:context=""http://www.example.com/$metadata#TestEntitySet"">" + "<id>http://host/TestEntitySet</id>" + "<title />"; Action<ODataWriter> deltaLinkAtWriteStart = (odataWriter) => { var feedToWrite = new ODataFeed { Id = new Uri("http://host/TestEntitySet", UriKind.Absolute), DeltaLink = new Uri("http://host/deltaLink", UriKind.Absolute) }; odataWriter.WriteStart(feedToWrite); }; WriteAnnotationsAndValidatePayload(deltaLinkAtWriteStart, ODataFormat.Atom, expectedPayload, request: false, createFeedWriter: true); }
public void WriteStartShouldIgnoreDeltaLinkWhenWritingRequestTopLevelFeed() { string expectedPayload = "{" + "\"@odata.context\":\"http://www.example.com/$metadata#TestEntitySet\"," + "\"value\":[]" + "}"; Action<ODataWriter> deltaLinkAtWriteStart = (odataWriter) => { var feedToWrite = new ODataFeed { DeltaLink = new Uri("http://host/deltaLink", UriKind.Absolute) }; odataWriter.WriteStart(feedToWrite); odataWriter.WriteEnd(); }; WriteAnnotationsAndValidatePayload(deltaLinkAtWriteStart, ODataFormat.Json, expectedPayload, request: true, createFeedWriter: true); }
public void CreateFeed_NoMetadata() { var feed = new ODataFeed<Item>(); feed.Feed = new List<Folder>() { GetFolder() }; (feed.Feed.First()).MetadataUrl = "https://labs.sf-api.com/sf/v3/$metadata#ShareFile.Api.Models.Folder"; ((feed.Feed.First() as Folder).Children.First()).MetadataUrl = "https://labs.sf-api.com/sf/v3/$metadata#ShareFile.Api.Models.File"; feed.MetadataUrl = ""; var serializer = GetSerializer(); StringWriter writer = new StringWriter(); serializer.Serialize(writer, feed); var jsonReader = new JsonTextReader(new StringReader(writer.ToString())); var item = serializer.Deserialize<ODataFeed<Item>>(jsonReader); item.Should().NotBeNull(); item.Feed.First().GetType().Should().Be(typeof(Folder)); }
private void ApplyFeedInNavigationProperty(IEdmNavigationProperty navigationProperty, object entityResource, ODataFeed feed, ODataDeserializerContext readContext) { ODataFeedAnnotation feedAnnotation = feed.GetAnnotation <ODataFeedAnnotation>(); Contract.Assert(feedAnnotation != null, "Each feed we create should gave annotation on it."); ODataEntryDeserializer deserializer = DeserializerProvider.GetODataDeserializer(navigationProperty.Type); object value = deserializer.ReadInline(feed, readContext); if (readContext.IsPatchMode) { throw Error.InvalidOperation(SRResources.CannotPatchNavigationProperties, navigationProperty.Name, navigationProperty.DeclaringEntityType().FullName()); } SetCollectionProperty(entityResource, navigationProperty.Name, isDelta: false, value: value); }
/// <summary> /// Reads one operation for the feed being read. /// </summary> /// <param name="feed">The feed to read.</param> /// <param name="metadataReferencePropertyName">The name of the metadata reference property being read.</param> /// <param name="insideArray">true if the operation value is inside an array, i.e. multiple targets for the operation; false otherwise.</param> private void ReadSingleOperationValue(ODataFeed feed, string metadataReferencePropertyName, bool insideArray) { Debug.Assert(feed != null, "feed != null"); Debug.Assert(!string.IsNullOrEmpty(metadataReferencePropertyName), "!string.IsNullOrEmpty(metadataReferencePropertyName)"); Debug.Assert(ODataJsonLightUtils.IsMetadataReferenceProperty(metadataReferencePropertyName), "ODataJsonLightReaderUtils.IsMetadataReferenceProperty(metadataReferencePropertyName)"); if (this.JsonReader.NodeType != JsonNodeType.StartObject) { throw new ODataException(ODataErrorStrings.ODataJsonOperationsDeserializerUtils_OperationsPropertyMustHaveObjectValue(metadataReferencePropertyName, this.JsonReader.NodeType)); } // read over the start-object node of the metadata object for the operations this.JsonReader.ReadStartObject(); var operation = this.CreateODataOperationAndAddToFeed(feed, metadataReferencePropertyName); // Ignore the unrecognized operation. if (operation == null) { while (this.JsonReader.NodeType == JsonNodeType.Property) { this.JsonReader.ReadPropertyName(); this.JsonReader.SkipValue(); } this.JsonReader.ReadEndObject(); return; } Debug.Assert(operation.Metadata != null, "operation.Metadata != null"); while (this.JsonReader.NodeType == JsonNodeType.Property) { string operationPropertyName = ODataAnnotationNames.RemoveAnnotationPrefix(this.JsonReader.ReadPropertyName()); switch (operationPropertyName) { case JsonConstants.ODataOperationTitleName: if (operation.Title != null) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_MultipleOptionalPropertiesInOperation(operationPropertyName, metadataReferencePropertyName)); } string titleString = this.JsonReader.ReadStringValue(JsonConstants.ODataOperationTitleName); ODataJsonLightValidationUtils.ValidateOperationPropertyValueIsNotNull(titleString, operationPropertyName, metadataReferencePropertyName); operation.Title = titleString; break; case JsonConstants.ODataOperationTargetName: if (operation.Target != null) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_MultipleOptionalPropertiesInOperation(operationPropertyName, metadataReferencePropertyName)); } string targetString = this.JsonReader.ReadStringValue(JsonConstants.ODataOperationTargetName); ODataJsonLightValidationUtils.ValidateOperationPropertyValueIsNotNull(targetString, operationPropertyName, metadataReferencePropertyName); operation.Target = this.ProcessUriFromPayload(targetString); break; default: // skip over all unknown properties and read the next property or // the end of the metadata for the current propertyName this.JsonReader.SkipValue(); break; } } if (operation.Target == null && insideArray) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_OperationMissingTargetProperty(metadataReferencePropertyName)); } // read the end-object node of the target / title pair this.JsonReader.ReadEndObject(); }
/// <summary> /// Write the given feed metadata in atom format /// </summary> /// <param name="feed">The feed for which to write the meadata or null if it is the metadata of an atom:source element.</param> /// <param name="updatedTime">Value for the atom:updated element.</param> /// <param name="authorWritten">Set to true if the author element was written, false otherwise.</param> internal void WriteFeedMetadata(ODataFeed feed, string updatedTime, out bool authorWritten) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(feed != null, "feed != null"); Debug.Assert(!string.IsNullOrEmpty(updatedTime), "!string.IsNullOrEmpty(updatedTime)"); #if DEBUG DateTimeOffset tempDateTimeOffset; Debug.Assert(DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset), "DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset)"); #endif AtomFeedMetadata feedMetadata = feed.GetAnnotation<AtomFeedMetadata>(); if (feedMetadata == null) { // create the required metadata elements with default values. // <atom:id>idValue</atom:id> Debug.Assert(!string.IsNullOrEmpty(feed.Id), "The feed Id should have been validated by now."); this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIdElementName, AtomConstants.AtomNamespace, feed.Id); // <atom:title></atom:title> this.WriteEmptyElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace); // <atom:updated>dateTimeOffset</atom:updated> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updatedTime); authorWritten = false; } else { this.atomFeedMetadataSerializer.WriteFeedMetadata(feedMetadata, feed, updatedTime, out authorWritten); } }
/// <summary> /// Writes the odata.count annotation for a feed if it has not been written yet (and the count is specified on the feed). /// </summary> /// <param name="feed">The feed to write the count for.</param> /// <param name="propertyName">The name of the expanded nav property or null for a top-level feed.</param> private void WriteFeedCount(ODataFeed feed, string propertyName) { Debug.Assert(feed != null, "feed != null"); // If we haven't written the count yet and it's available, write it. long? count = feed.Count; if (count.HasValue) { if (propertyName == null) { this.odataAnnotationWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataCount); } else { this.odataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataCount); } this.jsonWriter.WriteValue(count.Value); } }
/// <summary> /// Constructor to create a new feed scope. /// </summary> /// <param name="feed">The feed for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> internal JsonLightFeedScope(ODataFeed feed, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) : base(feed, navigationSource, entityType, skipWriting, selectedProperties, odataUri) { }
void IODataSerializationFeature.Apply(ODataFeed feed, ODataSerializationFeatureContext context) { }
public AsyncOperationScheduledException(ODataFeed<AsyncOperation> asyncOperation) { ScheduledOperations = asyncOperation; }
public void ExpandedLinkWithNullNavigationTests() { ODataNavigationLink expandedEntryLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink.IsCollection = false; ODataNavigationLink expandedEntryLink2 = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink2.IsCollection = false; expandedEntryLink2.Name = expandedEntryLink2.Name + "2"; ODataEntry defaultEntry = ObjectModelUtils.CreateDefaultEntry(); ODataFeed defaultFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntry nullEntry = ObjectModelUtils.ODataNullEntry; PayloadWriterTestDescriptor.WriterTestExpectedResultCallback successCallback = (testConfiguration) => { if (testConfiguration.Format == ODataFormat.Atom) { return(new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName).ToString(), FragmentExtractor = (result) => { return result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName); } }); } else { return(new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = "null", //new JsonPrimitiveValue(null).ToText(testConfiguration.MessageWriterSettings.Indent), FragmentExtractor = (result) => { return JsonUtils.UnwrapTopLevelValue(testConfiguration, result).Object().Properties.First(p => p.Name == ObjectModelUtils.DefaultLinkName).Value; } }); } }; Func <ExpectedException, PayloadWriterTestDescriptor.WriterTestExpectedResultCallback> errorCallback = (expectedException) => { return((testConfiguration) => { return new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = expectedException, }; }); }; var testCases = new PayloadWriterTestDescriptor <ODataItem>[] { // navigation to a null entry new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry }, successCallback), // navigation to a null entry twice new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry, null, null, expandedEntryLink2, nullEntry, null }, successCallback), // top level null entry. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), // navigation to a null entry twice in expanded link // this actually throws ArgumentNullException when WriteStart() for the second nullEntry is called since // the state has been changed from NavigationLink to ExpandedLink after the first one. // TODO: check if ArgumentNullException needs to change the WriterState. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry, null, nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), // Null entry inside a feed, same as above this throws ArgumentNullException but state is not put to error state. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultFeed, nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), }; // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testCases, this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent.Where(tc => tc.Format == ODataFormat.Atom), (testCase, testConfig) => { testConfig = testConfig.Clone(); testConfig.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testCase, testConfig, this.Assert, this.Logger); }); }
public void ExpandedLinkWithMultiplicityTests() { ODataNavigationLink expandedEntryLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink.IsCollection = false; ODataNavigationLink expandedFeedLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedFeedLink.IsCollection = true; ODataEntry defaultEntry = ObjectModelUtils.CreateDefaultEntry(); ODataFeed defaultFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntityReferenceLink defaultEntityReferenceLink = ObjectModelUtils.CreateDefaultEntityReferenceLink(); ODataEntry officeEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeType"); ODataEntry officeWithNumberEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeWithNumberType"); ODataEntry cityEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.CityType"); // CityHall is a nav prop with multiplicity '*' of type 'TestModel.OfficeType' ODataNavigationLink cityHallLinkIsCollectionNull = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ null); ODataNavigationLink cityHallLinkIsCollectionTrue = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ true); ODataNavigationLink cityHallLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ false); // PoliceStation is a nav prop with multiplicity '1' of type 'TestModel.OfficeType' ODataNavigationLink policeStationLinkIsCollectionNull = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ null); ODataNavigationLink policeStationLinkIsCollectionTrue = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ true); ODataNavigationLink policeStationLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ false); ExpectedException expandedEntryLinkWithFeedContentError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedContent", "http://odata.org/link"); ExpectedException expandedFeedLinkWithEntryContentError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryContent", "http://odata.org/link"); ExpectedException expandedFeedLinkWithEntryMetadataError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkWithFeedMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata", "http://odata.org/link"); ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorRequest = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithFeedPayloadAndEntryMetadata", "http://odata.org/link"); ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkPayloadWithFeedMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkPayloadWithFeedMetadataError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithEntryPayloadAndFeedMetadata", "http://odata.org/link"); ExpectedException multipleItemsInExpandedLinkError = ODataExpectedExceptions.ODataException("ODataWriterCore_MultipleItemsInNavigationLinkContent", "http://odata.org/link"); ExpectedException entityReferenceLinkInResponseError = ODataExpectedExceptions.ODataException("ODataWriterCore_EntityReferenceLinkInResponse"); IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); var testCases = new ExpandedLinkMultiplicityTestCase[] { #region IsCollection flag does not match payload new ExpandedLinkMultiplicityTestCase { // Expanded link with IsCollection is 'false' and feed payload Items = new ODataItem[] { defaultEntry, expandedEntryLink, defaultFeed }, ExpectedError = tc => expandedEntryLinkWithFeedContentError, }, new ExpandedLinkMultiplicityTestCase { // Expanded link with IsCollection is 'true' and entry payload Items = new ODataItem[] { defaultEntry, expandedFeedLink, defaultEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, }, #endregion IsCollection flag does not match payload #region IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection value and an entry of a non-matching entity type; Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, cityEntry }, ExpectedError = tc => tc.Format == ODataFormat.Atom || !tc.IsRequest ? ODataExpectedExceptions.ODataException("WriterValidationUtils_EntryTypeInExpandedLinkNotCompatibleWithNavigationPropertyType", "TestModel.CityType", "TestModel.OfficeType") : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection value and an entry of a matching entity type; no error expected. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection and an entry of a derived entity type; no error expected. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeWithNumberEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection value and an entry of a non-matching entity type; Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, cityEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? ODataExpectedExceptions.ODataException("WriterValidationUtils_EntryTypeInExpandedLinkNotCompatibleWithNavigationPropertyType", "TestModel.CityType", "TestModel.OfficeType") : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection value and an entry of a matching entity type; no error expected. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection and an entry of a derived entity type; no error expected. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeWithNumberEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, #endregion IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link #region Expanded link with entry content new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, officeEntry }, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, officeEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedEntryLinkPayloadWithFeedMetadataError : expandedEntryLinkPayloadWithFeedMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == true, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, officeEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, Model = model }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == null, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry }, ExpectedError = tc => tc.IsRequest || tc.Format == ODataFormat.Atom ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation") : null, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == null, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, officeEntry }, ExpectedError = tc => expandedEntryLinkPayloadWithFeedMetadataError, Model = model, }, #endregion Expanded collection link with entry content #region Expanded link with feed content new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == false, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultFeed, officeEntry }, ExpectedError = tc => expandedEntryLinkWithFeedContentError, }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedFeedLinkPayloadWithEntryMetadataErrorRequest : expandedFeedLinkPayloadWithEntryMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedEntryLinkWithFeedContentError : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultFeed, officeEntry }, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == null, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => expandedFeedLinkPayloadWithEntryMetadataErrorRequest, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == null, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest || tc.Format == ODataFormat.Atom ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall") : null, Model = model, }, #endregion Expanded collection link with entry content #region Expanded link with entity reference link content new ExpandedLinkMultiplicityTestCase { // Single ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : entityReferenceLinkInResponseError, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink }, ExpectedError = tc => expandedFeedLinkWithEntryMetadataError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => expandedFeedLinkWithEntryMetadataError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == false, collection nav prop; should not fail (metadata mismatch explicitly allowed). Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError, Model = model, }, //// NOTE: Not testing the cases where IsCollection == null here since ERL payloads are only allowed in //// requests where IsCollection is required (in ATOM and JSON) #endregion Expanded link with entity reference link content }; // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testCases, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => tc.Format == ODataFormat.Atom), (testCase, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); using (var memoryStream = new TestStream()) using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert, null, testCase.Model)) { ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false); TestExceptionUtils.ExpectedException( this.Assert, () => TestWriterUtils.WritePayload(messageWriter, writer, true, testCase.Items), testCase.ExpectedError == null ? null : testCase.ExpectedError(testConfiguration), this.ExceptionVerifier); } }); }
/// <summary> /// Creates the materializer link with a feed. /// </summary> /// <param name="link">The link.</param> /// <param name="feed">The feed.</param> /// <returns>The materializer link.</returns> public static MaterializerNavigationLink CreateLink(ODataNavigationLink link, ODataFeed feed) { Debug.Assert(link.GetAnnotation <MaterializerNavigationLink>() == null, "there should be no MaterializerNavigationLink annotation on the feed link yet"); MaterializerNavigationLink materializedNavigationLink = new MaterializerNavigationLink(link, feed); link.SetAnnotation <MaterializerNavigationLink>(materializedNavigationLink); return(materializedNavigationLink); }
public ODataFeedTests() { this.odataFeed = new ODataFeed(); }
/// <summary> /// Initializes a new instance of the <see cref="ReadingFeedArgs" /> class. /// </summary> /// <param name="feed">The feed.</param> public ReadingFeedArgs(ODataFeed feed) { Util.CheckArgumentNull(feed, "feed"); this.Feed = feed; }
/// <summary> /// Start writing a feed. /// </summary> /// <param name="feed">The feed to write.</param> protected override void StartFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); Debug.Assert( this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.HasValue || this.ParentNavigationLink.IsCollection.Value, "We should have already verified that the IsCollection matches the actual content of the link (feed/entry)."); // Verify non-empty ID // We require non-null, non-empty IDs on feeds since it is required by ATOM. if (feed.Id == null) { throw new ODataException(OData.Core.Strings.ODataAtomWriter_FeedsMustHaveNonEmptyId); } this.CheckAndWriteParentNavigationLinkStartForInlineElement(); // <atom:feed> this.atomOutputContext.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomFeedElementName, AtomConstants.AtomNamespace); if (this.IsTopLevel) { this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes(); // metadata:context this.atomEntryAndFeedSerializer.TryWriteFeedContextUri(this.CurrentFeedScope.GetOrCreateTypeContext(this.atomOutputContext.Model, this.atomOutputContext.WritingResponse)); if (feed.Count.HasValue) { this.atomEntryAndFeedSerializer.WriteCount(feed.Count.Value); } } bool authorWritten; this.atomEntryAndFeedSerializer.WriteFeedMetadata(feed, this.updatedTime, out authorWritten); this.CurrentFeedScope.AuthorWritten = authorWritten; this.WriteFeedInstanceAnnotations(feed, this.CurrentFeedScope); }
/// <summary> /// Visits a feed item. /// </summary> /// <param name="feed">The feed to visit.</param> protected override void VisitFeed(ODataFeed feed) { this.VisitAtomMetadata(feed.GetAnnotation <AtomFeedMetadata>()); base.VisitFeed(feed); }
/// <summary> /// Provide additional serialization information to the <see cref="ODataWriter"/> for <paramref name="feed"/>. /// </summary> /// <param name="feed">The instance to set the serialization info.</param> /// <param name="serializationInfo">The serialization info to set.</param> public static void SetSerializationInfo(this ODataFeed feed, ODataFeedAndEntrySerializationInfo serializationInfo) { ExceptionUtils.CheckArgumentNotNull(feed, "feed"); feed.SerializationInfo = serializationInfo; }
internal void WriteFeedMetadata(AtomFeedMetadata feedMetadata, ODataFeed feed, string updatedTime, out bool authorWritten) { Debug.Assert(feedMetadata != null, "Feed metadata must not be null!"); // <atom:id>text</atom:id> // NOTE: this is the Id of the feed. For a regular feed this is stored on the feed itself; // if used in the context of an <atom:source> element it is stored in metadata Uri id = feed == null ? feedMetadata.SourceId : feed.Id; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIdElementName, AtomConstants.AtomNamespace, id == null ? null : UriUtils.UriToString(id)); // <atom:title>text</atom:title> // NOTE: write an empty element if no title is specified since the element is required this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, feedMetadata.Title); if (feedMetadata.Subtitle != null) { // <atom:subtitle>text</atom:subtitle> this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSubtitleElementName, AtomConstants.AtomNamespace, feedMetadata.Subtitle); } // <atom:updated>date</atom:updated> // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. string updated = feedMetadata.Updated.HasValue ? ODataAtomConvert.ToAtomString(feedMetadata.Updated.Value) : updatedTime; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updated); AtomLinkMetadata selfLinkMetadata = feedMetadata.SelfLink; if (selfLinkMetadata != null) { AtomLinkMetadata mergedSelfLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata( selfLinkMetadata, AtomConstants.AtomSelfRelationAttributeValue, null /* href */, null /* title */, null /* media type */); this.WriteAtomLink(mergedSelfLinkMetadata, null /*etag*/); } IEnumerable <AtomLinkMetadata> links = feedMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { // DeltaLink is written from ODataFeed, so it shouldn't be written again from AtomFeedMetadata. if (link.Relation != AtomConstants.AtomDeltaRelationAttributeValue) { // <atom:link>...</atom:link> this.WriteAtomLink(link, null /* etag */); } } } IEnumerable <AtomCategoryMetadata> categories = feedMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { // <atom:category term="..." scheme="..." label="..."></atom:category> this.WriteCategory(category); } } Uri logo = feedMetadata.Logo; if (logo != null) { // <atom:logo>Uri</atom:logo> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLogoElementName, AtomConstants.AtomNamespace, this.UriToUrlAttributeValue(logo)); } if (feedMetadata.Rights != null) { // <atom:rights>rights</atom:rights> this.WriteTextConstruct( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, feedMetadata.Rights); } IEnumerable <AtomPersonMetadata> contributors = feedMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { // <atom:contributor>contributor data</atom:contributor> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(contributor); this.XmlWriter.WriteEndElement(); } } AtomGeneratorMetadata generator = feedMetadata.Generator; if (generator != null) { // <atom:generator uri="..." version="...">name</atom:generator> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomGeneratorElementName, AtomConstants.AtomNamespace); if (generator.Uri != null) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomGeneratorUriAttributeName, this.UriToUrlAttributeValue(generator.Uri)); } if (!string.IsNullOrEmpty(generator.Version)) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomGeneratorVersionAttributeName, generator.Version); } ODataAtomWriterUtils.WriteString(this.XmlWriter, generator.Name); this.XmlWriter.WriteEndElement(); } Uri icon = feedMetadata.Icon; if (icon != null) { // <atom:icon>Uri</atom:icon> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIconElementName, AtomConstants.AtomNamespace, this.UriToUrlAttributeValue(icon)); } IEnumerable <AtomPersonMetadata> authors = feedMetadata.Authors; authorWritten = false; if (authors != null) { foreach (AtomPersonMetadata author in authors) { // <atom:author>author data</atom:author> authorWritten = true; this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(author); this.XmlWriter.WriteEndElement(); } } }
/// <summary> /// Finish writing a feed. /// </summary> /// <param name="feed">The feed to write.</param> protected override void EndFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); if (this.ParentNavigationLink == null && this.writingParameter) { // End the array which holds the entries in the feed. this.jsonWriter.EndArrayScope(); } else if (this.ParentNavigationLink == null) { // End the array which holds the entries in the feed. this.jsonWriter.EndArrayScope(); // Write custom instance annotations this.jsonLightEntryAndFeedSerializer.InstanceAnnotationWriter.WriteInstanceAnnotations(feed.InstanceAnnotations, this.CurrentFeedScope.InstanceAnnotationWriteTracker); if (this.jsonLightOutputContext.WritingResponse) { // Write the next link if it's available. this.WriteFeedNextLink(feed, /*propertyName*/null); // Write the delta link if it's available. this.WriteFeedDeltaLink(feed); } // Close the object wrapper. this.jsonWriter.EndObjectScope(); } else { Debug.Assert( this.ParentNavigationLink != null && this.ParentNavigationLink.IsCollection.HasValue && this.ParentNavigationLink.IsCollection.Value, "We should have verified that feeds can only be written into IsCollection = true links in requests."); string propertyName = this.ParentNavigationLink.Name; this.ValidateNoDeltaLinkForExpandedFeed(feed); this.ValidateNoCustomInstanceAnnotationsForExpandedFeed(feed); if (this.jsonLightOutputContext.WritingResponse) { // End the array which holds the entries in the feed. // NOTE: in requests we will only write the EndArray of a feed // when we hit the navigation link end since a navigation link // can contain multiple feeds that get collapesed into a single array value. this.jsonWriter.EndArrayScope(); // Write the next link if it's available. this.WriteFeedNextLink(feed, propertyName); } } }
public override System.Threading.Tasks.Task WriteStartAsync(ODataFeed feed) { throw new NotImplementedException(); }
/// <summary> /// Writes the odata.deltaLink annotation for a feed if it has not been written yet (and the delta link is specified on the feed). /// </summary> /// <param name="feed">The feed to write the delta link for.</param> private void WriteFeedDeltaLink(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); // If we haven't written the delta link yet and it's available, write it. Uri deltaLink = feed.DeltaLink; if (deltaLink != null && !this.CurrentFeedScope.DeltaLinkWritten) { this.odataAnnotationWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataDeltaLink); this.jsonWriter.WriteValue(this.jsonLightEntryAndFeedSerializer.UriToString(deltaLink)); this.CurrentFeedScope.DeltaLinkWritten = true; } }
/// <summary> /// Start writing a feed. /// </summary> /// <param name="feed">The feed to write.</param> protected override void StartFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); IJsonWriter jsonWriter = this.jsonLightOutputContext.JsonWriter; if (this.ParentNavigationLink == null) { // Top-level feed. // "{" jsonWriter.StartObjectScope(); // @odata.context this.jsonLightEntryAndFeedSerializer.WriteFeedContextUri(this.CurrentFeedScope.GetOrCreateTypeContext(this.jsonLightOutputContext.Model, this.jsonLightOutputContext.WritingResponse)); if (this.jsonLightOutputContext.WritingResponse) { // Write the inline count if it's available. this.WriteFeedCount(feed, /*propertyName*/ null); // Write the next link if it's available. this.WriteFeedNextLink(feed, /*propertyName*/ null); // Write the delta link if it's available. this.WriteFeedDeltaLink(feed); } // Write custom instance annotations this.jsonLightEntryAndFeedSerializer.InstanceAnnotationWriter.WriteInstanceAnnotations(feed.InstanceAnnotations, this.CurrentFeedScope.InstanceAnnotationWriteTracker); // "value": jsonWriter.WriteValuePropertyName(); // Start array which will hold the entries in the feed. jsonWriter.StartArrayScope(); } else { // Expanded feed. Debug.Assert( this.ParentNavigationLink != null && this.ParentNavigationLink.IsCollection.HasValue && this.ParentNavigationLink.IsCollection.Value, "We should have verified that feeds can only be written into IsCollection = true links in requests."); string propertyName = this.ParentNavigationLink.Name; this.ValidateNoDeltaLinkForExpandedFeed(feed); this.ValidateNoCustomInstanceAnnotationsForExpandedFeed(feed); if (this.jsonLightOutputContext.WritingResponse) { // Write the inline count if it's available. this.WriteFeedCount(feed, propertyName); // Write the next link if it's available. this.WriteFeedNextLink(feed, propertyName); // And then write the property name to start the value. jsonWriter.WriteName(propertyName); // Start array which will hold the entries in the feed. jsonWriter.StartArrayScope(); } else { JsonLightNavigationLinkScope navigationLinkScope = (JsonLightNavigationLinkScope)this.ParentNavigationLinkScope; if (!navigationLinkScope.FeedWritten) { // Close the entity reference link array (if written) if (navigationLinkScope.EntityReferenceLinkWritten) { jsonWriter.EndArrayScope(); } // And then write the property name to start the value. jsonWriter.WriteName(propertyName); // Start array which will hold the entries in the feed. jsonWriter.StartArrayScope(); navigationLinkScope.FeedWritten = true; } } } }
public void WritingFeedWithFunctionAndAction() { ODataFeed feed = new ODataFeed(); feed.AddAction(new ODataAction { Metadata = new Uri("http://example.org/odata.svc/$metadata#Action"), Target = new Uri("http://example.org/odata.svc/DoAction"), Title = "ActionTitle" }); feed.AddFunction(new ODataFunction() { Metadata = new Uri("http://example.org/odata.svc/$metadata#Function"), Target = new Uri("http://example.org/odata.svc/DoFunction"), Title = "FunctionTitle" }); ODataItem[] itemsToWrite = new ODataItem[] { feed, this.entryWithOnlyData1, }; string result = this.GetWriterOutputForContentTypeAndKnobValue("application/json;odata.metadata=minimal", true, itemsToWrite, Model, EntitySet, EntityType); const string expectedPayload = "{\"" + "@odata.context\":\"http://example.org/odata.svc/$metadata#EntitySet\"," + "\"#Action\":{" + "\"title\":\"ActionTitle\"," + "\"target\":\"http://example.org/odata.svc/DoAction\"" + "}," + "\"#Function\":{" + "\"title\":\"FunctionTitle\"," + "\"target\":\"http://example.org/odata.svc/DoFunction\"" + "}," + "\"value\":[" + "{" + "\"ID\":101,\"Name\":\"Alice\"" + "}" + "]" + "}"; result.Should().Be(expectedPayload); }
/// <summary> /// Create a new feed scope. /// </summary> /// <param name="feed">The feed for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <returns>The newly create scope.</returns> protected override FeedScope CreateFeedScope(ODataFeed feed, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { return(new JsonLightFeedScope(feed, navigationSource, entityType, skipWriting, selectedProperties, odataUri)); }
/// <summary> /// Read the metadata reference property value for the feed being read. /// </summary> /// <param name="feed">The feed to read.</param> /// <param name="metadataReferencePropertyName">The name of the metadata reference property being read.</param> private void ReadMetadataReferencePropertyValue(ODataFeed feed, string metadataReferencePropertyName) { Debug.Assert(feed != null, "feed != null"); Debug.Assert(!string.IsNullOrEmpty(metadataReferencePropertyName), "!string.IsNullOrEmpty(metadataReferencePropertyName)"); Debug.Assert(metadataReferencePropertyName.IndexOf(ODataConstants.ContextUriFragmentIndicator) > -1, "metadataReferencePropertyName.IndexOf(JsonLightConstants.ContextUriFragmentIndicator) > -1"); this.JsonReader.AssertNotBuffering(); this.ValidateCanReadMetadataReferenceProperty(); // Validate that the property name is a valid absolute URI or a valid URI fragment. ODataJsonLightValidationUtils.ValidateMetadataReferencePropertyName(this.ContextUriParseResult.MetadataDocumentUri, metadataReferencePropertyName); bool insideArray = false; if (this.JsonReader.NodeType == JsonNodeType.StartArray) { this.JsonReader.ReadStartArray(); insideArray = true; } do { this.ReadSingleOperationValue(feed, metadataReferencePropertyName, insideArray); } while (insideArray && this.JsonReader.NodeType != JsonNodeType.EndArray); if (insideArray) { this.JsonReader.ReadEndArray(); } this.JsonReader.AssertNotBuffering(); this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); }
protected override void EndFeed(ODataFeed feed) { throw new NotImplementedException(); }
internal void WriteFeedMetadata(AtomFeedMetadata feedMetadata, ODataFeed feed, string updatedTime, out bool authorWritten) { string textContent = (feed == null) ? feedMetadata.SourceId : feed.Id; base.WriteElementWithTextContent("", "id", "http://www.w3.org/2005/Atom", textContent); base.WriteTextConstruct("", "title", "http://www.w3.org/2005/Atom", feedMetadata.Title); if (feedMetadata.Subtitle != null) { base.WriteTextConstruct("", "subtitle", "http://www.w3.org/2005/Atom", feedMetadata.Subtitle); } string str2 = feedMetadata.Updated.HasValue ? ODataAtomConvert.ToAtomString(feedMetadata.Updated.Value) : updatedTime; base.WriteElementWithTextContent("", "updated", "http://www.w3.org/2005/Atom", str2); AtomLinkMetadata selfLink = feedMetadata.SelfLink; if (selfLink != null) { AtomLinkMetadata linkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(selfLink, "self", null, null, null); base.WriteAtomLink(linkMetadata, null); } IEnumerable <AtomLinkMetadata> links = feedMetadata.Links; if (links != null) { foreach (AtomLinkMetadata metadata3 in links) { base.WriteAtomLink(metadata3, null); } } IEnumerable <AtomCategoryMetadata> categories = feedMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata metadata4 in categories) { base.WriteCategory(metadata4); } } Uri logo = feedMetadata.Logo; if (logo != null) { base.WriteElementWithTextContent("", "logo", "http://www.w3.org/2005/Atom", base.UriToUrlAttributeValue(logo)); } if (feedMetadata.Rights != null) { base.WriteTextConstruct("", "rights", "http://www.w3.org/2005/Atom", feedMetadata.Rights); } IEnumerable <AtomPersonMetadata> contributors = feedMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata metadata5 in contributors) { base.XmlWriter.WriteStartElement("", "contributor", "http://www.w3.org/2005/Atom"); base.WritePersonMetadata(metadata5); base.XmlWriter.WriteEndElement(); } } AtomGeneratorMetadata generator = feedMetadata.Generator; if (generator != null) { base.XmlWriter.WriteStartElement("", "generator", "http://www.w3.org/2005/Atom"); if (generator.Uri != null) { base.XmlWriter.WriteAttributeString("uri", base.UriToUrlAttributeValue(generator.Uri)); } if (!string.IsNullOrEmpty(generator.Version)) { base.XmlWriter.WriteAttributeString("version", generator.Version); } ODataAtomWriterUtils.WriteString(base.XmlWriter, generator.Name); base.XmlWriter.WriteEndElement(); } Uri icon = feedMetadata.Icon; if (icon != null) { base.WriteElementWithTextContent("", "icon", "http://www.w3.org/2005/Atom", base.UriToUrlAttributeValue(icon)); } IEnumerable <AtomPersonMetadata> authors = feedMetadata.Authors; authorWritten = false; if (authors != null) { foreach (AtomPersonMetadata metadata7 in authors) { authorWritten = true; base.XmlWriter.WriteStartElement("", "author", "http://www.w3.org/2005/Atom"); base.WritePersonMetadata(metadata7); base.XmlWriter.WriteEndElement(); } } }
public void QueryWithOrderBy() { Dictionary <string, int> testCases = new Dictionary <string, int>() { { "Customers?$orderby=PersonID", -1 }, //-1 means the current PersonID is smaller than the next one. { "Customers?$orderby=PersonID mul @factor&@factor=-1", 1 }, //-1 means the current PersonID is bigger than the next one. { "Customers?$orderby=PersonID mul @factor desc&@factor=-1", -1 }, }; ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings() { BaseUri = ServiceBaseUri }; foreach (var testCase in testCases) { foreach (var mimeType in mimeTypes) { var requestMessage = new HttpWebRequestMessage(new Uri(ServiceBaseUri.AbsoluteUri + testCase.Key, UriKind.Absolute)); requestMessage.SetHeader("Accept", mimeType); var responseMessage = requestMessage.GetResponse(); Assert.AreEqual(200, responseMessage.StatusCode); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { ODataEntry entry1 = null; ODataEntry entry2 = null; ODataFeed feed = null; using (var messageReader = new ODataMessageReader(responseMessage, readerSettings, Model)) { var reader = messageReader.CreateODataFeedReader(); while (reader.Read()) { if (reader.State == ODataReaderState.EntryEnd) { if (null == entry1) { entry1 = reader.Item as ODataEntry; } else { entry2 = reader.Item as ODataEntry; } } else if (reader.State == ODataReaderState.FeedEnd) { feed = reader.Item as ODataFeed; } } } Assert.IsNotNull(feed); Assert.AreEqual(testCase.Value, String.Compare( entry1.Properties.Single(p => p.Name == "PersonID").Value.ToString(), entry2.Properties.Single(p => p.Name == "PersonID").Value.ToString())); } } } }
/// <summary> /// Writes the collection of <see cref="ODataInstanceAnnotation"/> for the given <paramref name="feed"/> to the ATOM payload. /// </summary> /// <param name="feed">The feed to write the <see cref="ODataInstanceAnnotation"/> for.</param> /// <param name="currentFeedScope">The current feed scope.</param> private void WriteFeedInstanceAnnotations(ODataFeed feed, AtomFeedScope currentFeedScope) { if (this.IsTopLevel) { this.WriteInstanceAnnotations(feed.InstanceAnnotations, currentFeedScope.InstanceAnnotationWriteTracker); } else { if (feed.InstanceAnnotations.Count > 0) { throw new ODataException(OData.Core.Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedFeed); } } }
internal static ODataItem ReadEntryOrFeed(ODataReader odataReader, ODataDeserializerContext readContext) { ODataItem topLevelItem = null; Stack <ODataItem> itemsStack = new Stack <ODataItem>(); while (odataReader.Read()) { switch (odataReader.State) { case ODataReaderState.EntryStart: ODataEntry entry = (ODataEntry)odataReader.Item; ODataEntryAnnotation entryAnnotation = null; if (entry != null) { entryAnnotation = new ODataEntryAnnotation(); entry.SetAnnotation(entryAnnotation); } if (itemsStack.Count == 0) { Contract.Assert(entry != null, "The top-level entry can never be null."); topLevelItem = entry; } else { ODataItem parentItem = itemsStack.Peek(); ODataFeed parentFeed = parentItem as ODataFeed; if (parentFeed != null) { ODataFeedAnnotation parentFeedAnnotation = parentFeed.GetAnnotation <ODataFeedAnnotation>(); Contract.Assert(parentFeedAnnotation != null, "Every feed we added to the stack should have the feed annotation on it."); parentFeedAnnotation.Add(entry); } else { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)parentItem; ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); Contract.Assert(parentNavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child."); Contract.Assert(parentNavigationLinkAnnotation.Count == 0, "Each navigation property can contain only one entry as its direct child."); parentNavigationLinkAnnotation.Add(entry); } } itemsStack.Push(entry); RecurseEnter(readContext); break; case ODataReaderState.EntryEnd: Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The entry which is ending should be on the top of the items stack."); itemsStack.Pop(); RecurseLeave(readContext); break; case ODataReaderState.NavigationLinkStart: ODataNavigationLink navigationLink = (ODataNavigationLink)odataReader.Item; Contract.Assert(navigationLink != null, "Navigation link should never be null."); navigationLink.SetAnnotation(new ODataNavigationLinkAnnotation()); Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item."); { ODataEntry parentEntry = (ODataEntry)itemsStack.Peek(); ODataEntryAnnotation parentEntryAnnotation = parentEntry.GetAnnotation <ODataEntryAnnotation>(); Contract.Assert(parentEntryAnnotation != null, "Every entry we added to the stack should have the entry annotation on it."); parentEntryAnnotation.Add(navigationLink); } itemsStack.Push(navigationLink); RecurseEnter(readContext); break; case ODataReaderState.NavigationLinkEnd: Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The navigation link which is ending should be on the top of the items stack."); itemsStack.Pop(); RecurseLeave(readContext); break; case ODataReaderState.FeedStart: ODataFeed feed = (ODataFeed)odataReader.Item; Contract.Assert(feed != null, "Feed should never be null."); feed.SetAnnotation(new ODataFeedAnnotation()); if (itemsStack.Count > 0) { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)itemsStack.Peek(); Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link."); ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); Contract.Assert(parentNavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child."); parentNavigationLinkAnnotation.Add(feed); } else { topLevelItem = feed; } itemsStack.Push(feed); RecurseEnter(readContext); break; case ODataReaderState.FeedEnd: Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The feed which is ending should be on the top of the items stack."); itemsStack.Pop(); RecurseLeave(readContext); break; case ODataReaderState.EntityReferenceLink: ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)odataReader.Item; Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null."); Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item."); { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)itemsStack.Peek(); ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); parentNavigationLinkAnnotation.Add(entityReferenceLink); } break; default: Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state."); break; } } Contract.Assert(odataReader.State == ODataReaderState.Completed, "We should have consumed all of the input by now."); Contract.Assert(topLevelItem != null, "A top level entry or feed should have been read by now."); return(topLevelItem); }
/// <summary> /// Writes the delta link for a feed. /// </summary> /// <param name="feed">The feed to write the delta link for.</param> internal void WriteFeedDeltaLink(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); Uri deltaLink = feed.DeltaLink; if (deltaLink != null) { // <atom:link rel="http://docs.oasis-open.org/odata/ns/delta" href="delta-link" /> this.WriteFeedLink( feed, AtomConstants.AtomDeltaRelationAttributeValue, deltaLink, (feedMetadata) => feedMetadata == null ? null : feedMetadata.Links.FirstOrDefault(link => link.Relation == AtomConstants.AtomDeltaRelationAttributeValue)); } }
/// <summary> /// Finish writing a feed. /// </summary> /// <param name="feed">The feed to write.</param> protected override void EndFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); Debug.Assert( this.ParentNavigationLink == null || this.ParentNavigationLink.IsCollection.Value, "We should have already verified that the IsCollection matches the actual content of the link (feed/entry)."); AtomFeedScope currentFeedScope = this.CurrentFeedScope; if (!currentFeedScope.AuthorWritten && currentFeedScope.EntryCount == 0) { // Write an empty author if there were no entries, since the feed must have an author if the entries don't have one as per ATOM spec this.atomEntryAndFeedSerializer.WriteFeedDefaultAuthor(); } this.WriteFeedInstanceAnnotations(feed, currentFeedScope); this.atomEntryAndFeedSerializer.WriteFeedNextPageLink(feed); // Write delta link only in case of writing response for a top level feed. if (this.IsTopLevel) { if (this.atomOutputContext.WritingResponse) { this.atomEntryAndFeedSerializer.WriteFeedDeltaLink(feed); } } else { this.ValidateNoDeltaLinkForExpandedFeed(feed); } // </atom:feed> this.atomOutputContext.XmlWriter.WriteEndElement(); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); }
public void InitTest() { this.odataFeed = new ODataFeed(); }
/// <summary> /// Writes the next page link for a feed. /// </summary> /// <param name="feed">The feed to write the next page link for.</param> internal void WriteFeedNextPageLink(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); Uri nextPageLink = feed.NextPageLink; if (nextPageLink != null) { // <atom:link rel="next" href="next-page-link" /> this.WriteFeedLink( feed, AtomConstants.AtomNextRelationAttributeValue, nextPageLink, (feedMetadata) => feedMetadata == null ? null : feedMetadata.NextPageLink); } }
/// <summary> /// Reads an entry from the <paramref name="odataReader"/> and all it's children including expanded entries and feeds. /// </summary> /// <param name="odataReader">The ODataReader to read from.</param> /// <param name="topLevelSegmentInfo">The segment info for the top-level entry to read.</param> /// <returns>The <see cref="ODataEntry"/> with annotations which store the navigation links and their expanded values.</returns> private ODataEntry ReadEntry(ODataReader odataReader, SegmentInfo topLevelSegmentInfo) { Debug.Assert(odataReader != null, "odataReader != null"); Debug.Assert(odataReader.State == ODataReaderState.Start, "The ODataReader must not have been used yet."); Debug.Assert(topLevelSegmentInfo != null, "topLevelSegmentInfo != null"); ODataEntry topLevelEntry = null; Stack <ODataItem> itemsStack = new Stack <ODataItem>(); while (odataReader.Read()) { // Don't let the item stack grow larger than we can process later. Also lets us to fail and report the recursion depth limit error before ODL does. if (itemsStack.Count >= RecursionLimit) { throw DataServiceException.CreateDeepRecursion(RecursionLimit); } switch (odataReader.State) { case ODataReaderState.EntryStart: ODataEntry entry = (ODataEntry)odataReader.Item; ODataEntryAnnotation entryAnnotation = null; if (entry != null) { entryAnnotation = new ODataEntryAnnotation(); entry.SetAnnotation(entryAnnotation); } if (itemsStack.Count == 0) { Debug.Assert(entry != null, "The top-level entry can never be null."); topLevelEntry = entry; // For top-level entry, create the entry resource here. // This is needed since the creation of the resource may fail (especially if this is an update in which case // we evaluate the URL query, which may return no results and thus we would fail with 404) // and we need to report that failure rather then potential other failures caused by the properties in the entry in question. this.CreateEntityResource(topLevelSegmentInfo, entry, entryAnnotation, /*topLevel*/ true); } else { ODataItem parentItem = itemsStack.Peek(); ODataFeed parentFeed = parentItem as ODataFeed; if (parentFeed != null) { ODataFeedAnnotation parentFeedAnnotation = parentFeed.GetAnnotation <ODataFeedAnnotation>(); Debug.Assert(parentFeedAnnotation != null, "Every feed we added to the stack should have the feed annotation on it."); parentFeedAnnotation.Add(entry); } else { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)parentItem; ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); Debug.Assert(parentNavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child."); Debug.Assert(parentNavigationLinkAnnotation.Count == 0, "Each navigation property can contain only one entry as its direct child."); parentNavigationLinkAnnotation.Add(entry); } } itemsStack.Push(entry); break; case ODataReaderState.EntryEnd: Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The entry which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.NavigationLinkStart: ODataNavigationLink navigationLink = (ODataNavigationLink)odataReader.Item; Debug.Assert(navigationLink != null, "Navigation link should never be null."); navigationLink.SetAnnotation(new ODataNavigationLinkAnnotation()); Debug.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item."); { ODataEntry parentEntry = (ODataEntry)itemsStack.Peek(); ODataEntryAnnotation parentEntryAnnotation = parentEntry.GetAnnotation <ODataEntryAnnotation>(); Debug.Assert(parentEntryAnnotation != null, "Every entry we added to the stack should have the navigation link annotation on it."); parentEntryAnnotation.Add(navigationLink); } itemsStack.Push(navigationLink); break; case ODataReaderState.NavigationLinkEnd: Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The navigation link which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.FeedStart: ODataFeed feed = (ODataFeed)odataReader.Item; Debug.Assert(feed != null, "Feed should never be null."); feed.SetAnnotation(new ODataFeedAnnotation()); Debug.Assert(itemsStack.Count > 0, "Since we always start reading entry, we should never get a feed as the top-level item."); { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)itemsStack.Peek(); ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); Debug.Assert(parentNavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child."); parentNavigationLinkAnnotation.Add(feed); } itemsStack.Push(feed); break; case ODataReaderState.FeedEnd: Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The feed which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.EntityReferenceLink: ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)odataReader.Item; Debug.Assert(entityReferenceLink != null, "Entity reference link should never be null."); Debug.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item."); { ODataNavigationLink parentNavigationLink = (ODataNavigationLink)itemsStack.Peek(); ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>(); Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it."); parentNavigationLinkAnnotation.Add(entityReferenceLink); } break; default: Debug.Assert(false, "We should never get here, it means the ODataReader reported a wrong state."); break; } } Debug.Assert(odataReader.State == ODataReaderState.Completed, "We should have consumed all of the input by now."); Debug.Assert(topLevelEntry != null, "A top level entry should have been read by now."); return(topLevelEntry); }
/// <summary> /// Writes a feed link. /// </summary> /// <param name="feed">The feed that contains the link.</param> /// <param name="relation">Relation attribute of the link.</param> /// <param name="href">href attribute of the link.</param> /// <param name="getLinkMetadata">Function to get the AtomLinkMetadata for the feed link.</param> internal void WriteFeedLink(ODataFeed feed, string relation, Uri href, Func<AtomFeedMetadata, AtomLinkMetadata> getLinkMetadata) { AtomFeedMetadata feedMetadata = feed.GetAnnotation<AtomFeedMetadata>(); AtomLinkMetadata mergedLink = ODataAtomWriterMetadataUtils.MergeLinkMetadata( getLinkMetadata(feedMetadata), relation, href, null, /*title*/ null /*mediaType*/); this.atomFeedMetadataSerializer.WriteAtomLink(mergedLink, null); }
private void WriteFeed(object graph, ODataWriter writer, ODataSerializerContext writeContext) { IEnumerable enumerable = graph as IEnumerable; // Data to serialize if (enumerable != null) { ODataFeed feed = new ODataFeed(); if (writeContext.EntitySet != null) { IEntitySetLinkBuilder linkBuilder = SerializerProvider.EdmModel.GetEntitySetLinkBuilder(writeContext.EntitySet); Uri feedSelfLink = linkBuilder.BuildFeedSelfLink(new FeedContext(writeContext.EntitySet, writeContext.UrlHelper, graph)); if (feedSelfLink != null) { feed.SetAnnotation(new AtomFeedMetadata() { SelfLink = new AtomLinkMetadata() { Relation = SelfLinkRelation, Href = feedSelfLink } }); } } // TODO: Bug 467590: remove the hardcoded feed id. Get support for it from the model builder ? feed.Id = FeedNamespace + _edmCollectionType.FullName(); // If we have more OData format specific information apply it now. ODataResult odataFeedAnnotations = graph as ODataResult; if (odataFeedAnnotations != null) { feed.Count = odataFeedAnnotations.Count; feed.NextPageLink = odataFeedAnnotations.NextPageLink; } else { object nextPageLinkPropertyValue; HttpRequestMessage request = writeContext.Request; if (request != null && request.Properties.TryGetValue(ODataQueryOptions.NextPageLinkPropertyKey, out nextPageLinkPropertyValue)) { Uri nextPageLink = nextPageLinkPropertyValue as Uri; if (nextPageLink != null) { feed.NextPageLink = nextPageLink; } } } writer.WriteStart(feed); foreach (object entry in enumerable) { if (entry == null) { throw Error.NotSupported(SRResources.NullElementInCollection); } ODataSerializer entrySerializer = SerializerProvider.GetODataPayloadSerializer(entry.GetType()); if (entrySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, entry.GetType(), typeof(ODataMediaTypeFormatter).Name); } Contract.Assert(entrySerializer.ODataPayloadKind == ODataPayloadKind.Entry); entrySerializer.WriteObjectInline(entry, writer, writeContext); } writer.WriteEnd(); } }
/// <summary> /// Start writing a feed. /// </summary> /// <param name="feed">The feed to write.</param> protected override void StartFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); if (this.ParentNavigationLink == null && this.writingParameter) { // Start array which will hold the entries in the feed. this.jsonWriter.StartArrayScope(); } else if (this.ParentNavigationLink == null) { // Top-level feed. // "{" this.jsonWriter.StartObjectScope(); // @odata.context this.jsonLightEntryAndFeedSerializer.WriteFeedContextUri(this.CurrentFeedScope.GetOrCreateTypeContext(this.jsonLightOutputContext.Model, this.jsonLightOutputContext.WritingResponse)); if (this.jsonLightOutputContext.WritingResponse) { // write "odata.actions" metadata IEnumerable<ODataAction> actions = feed.Actions; if (actions != null) { this.jsonLightEntryAndFeedSerializer.WriteOperations(actions.Cast<ODataOperation>(), /*isAction*/ true); } // write "odata.functions" metadata IEnumerable<ODataFunction> functions = feed.Functions; if (functions != null) { this.jsonLightEntryAndFeedSerializer.WriteOperations(functions.Cast<ODataOperation>(), /*isAction*/ false); } // Write the inline count if it's available. this.WriteFeedCount(feed, /*propertyName*/null); // Write the next link if it's available. this.WriteFeedNextLink(feed, /*propertyName*/null); // Write the delta link if it's available. this.WriteFeedDeltaLink(feed); } // Write custom instance annotations this.jsonLightEntryAndFeedSerializer.InstanceAnnotationWriter.WriteInstanceAnnotations(feed.InstanceAnnotations, this.CurrentFeedScope.InstanceAnnotationWriteTracker); // "value": this.jsonWriter.WriteValuePropertyName(); // Start array which will hold the entries in the feed. this.jsonWriter.StartArrayScope(); } else { // Expanded feed. Debug.Assert( this.ParentNavigationLink != null && this.ParentNavigationLink.IsCollection.HasValue && this.ParentNavigationLink.IsCollection.Value, "We should have verified that feeds can only be written into IsCollection = true links in requests."); string propertyName = this.ParentNavigationLink.Name; this.ValidateNoDeltaLinkForExpandedFeed(feed); this.ValidateNoCustomInstanceAnnotationsForExpandedFeed(feed); if (this.jsonLightOutputContext.WritingResponse) { // Write the inline count if it's available. this.WriteFeedCount(feed, propertyName); // Write the next link if it's available. this.WriteFeedNextLink(feed, propertyName); // And then write the property name to start the value. this.jsonWriter.WriteName(propertyName); // Start array which will hold the entries in the feed. this.jsonWriter.StartArrayScope(); } else { JsonLightNavigationLinkScope navigationLinkScope = (JsonLightNavigationLinkScope)this.ParentNavigationLinkScope; if (!navigationLinkScope.FeedWritten) { // Close the entity reference link array (if written) if (navigationLinkScope.EntityReferenceLinkWritten) { this.jsonWriter.EndArrayScope(); } // And then write the property name to start the value. this.jsonWriter.WriteName(propertyName); // Start array which will hold the entries in the feed. this.jsonWriter.StartArrayScope(); navigationLinkScope.FeedWritten = true; } } } }
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)); }
/// <summary> /// Create a new feed scope. /// </summary> /// <param name="feed">The feed for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <returns>The newly create scope.</returns> protected override FeedScope CreateFeedScope(ODataFeed feed, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { return new JsonLightFeedScope(feed, navigationSource, entityType, skipWriting, selectedProperties, odataUri); }
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)); }
/// <summary> /// Writes the odata.nextLink annotation for a feed if it has not been written yet (and the next link is specified on the feed). /// </summary> /// <param name="feed">The feed to write the next link for.</param> /// <param name="propertyName">The name of the expanded nav property or null for a top-level feed.</param> private void WriteFeedNextLink(ODataFeed feed, string propertyName) { Debug.Assert(feed != null, "feed != null"); // If we haven't written the next link yet and it's available, write it. Uri nextPageLink = feed.NextPageLink; if (nextPageLink != null && !this.CurrentFeedScope.NextPageLinkWritten) { if (propertyName == null) { this.odataAnnotationWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNextLink); } else { this.odataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataNextLink); } this.jsonWriter.WriteValue(this.jsonLightEntryAndFeedSerializer.UriToString(nextPageLink)); this.CurrentFeedScope.NextPageLinkWritten = true; } }
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 void ValidateNoCustomInstanceAnnotationsForExpandedFeed(ODataFeed feed) { Debug.Assert(feed != null, "feed != null"); Debug.Assert( this.ParentNavigationLink != null && this.ParentNavigationLink.IsCollection.HasValue && this.ParentNavigationLink.IsCollection.Value == true, "This should only be called when writing an expanded feed."); if (feed.InstanceAnnotations.Count > 0) { throw new ODataException(OData.Core.Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedFeed); } }
/// <summary> /// Reads an ODataFeed or an ODataItem from the reader. /// </summary> /// <param name="reader">The OData reader to read from.</param> /// <returns>The read feed or entry.</returns> public static ODataItemBase ReadEntryOrFeed(ODataReader reader) { if (reader == null) { throw Error.ArgumentNull("odataReader"); } ODataItemBase topLevelItem = null; Stack <ODataItemBase> itemsStack = new Stack <ODataItemBase>(); while (reader.Read()) { switch (reader.State) { case ODataReaderState.EntryStart: ODataEntry entry = (ODataEntry)reader.Item; ODataEntryWithNavigationLinks entryWrapper = null; if (entry != null) { entryWrapper = new ODataEntryWithNavigationLinks(entry); } if (itemsStack.Count == 0) { Contract.Assert(entry != null, "The top-level entry can never be null."); topLevelItem = entryWrapper; } else { ODataItemBase parentItem = itemsStack.Peek(); ODataFeedWithEntries parentFeed = parentItem as ODataFeedWithEntries; if (parentFeed != null) { parentFeed.Entries.Add(entryWrapper); } else { ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)parentItem; Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child."); Contract.Assert(parentNavigationLink.NestedItems.Count == 0, "Each navigation property can contain only one entry as its direct child."); parentNavigationLink.NestedItems.Add(entryWrapper); } } itemsStack.Push(entryWrapper); break; case ODataReaderState.EntryEnd: Contract.Assert(itemsStack.Count > 0 && (reader.Item == null || itemsStack.Peek().Item == reader.Item), "The entry which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.NavigationLinkStart: ODataNavigationLink navigationLink = (ODataNavigationLink)reader.Item; Contract.Assert(navigationLink != null, "Navigation link should never be null."); ODataNavigationLinkWithItems navigationLinkWrapper = new ODataNavigationLinkWithItems(navigationLink); Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item."); { ODataEntryWithNavigationLinks parentEntry = (ODataEntryWithNavigationLinks)itemsStack.Peek(); parentEntry.NavigationLinks.Add(navigationLinkWrapper); } itemsStack.Push(navigationLinkWrapper); break; case ODataReaderState.NavigationLinkEnd: Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The navigation link which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.FeedStart: ODataFeed feed = (ODataFeed)reader.Item; Contract.Assert(feed != null, "Feed should never be null."); ODataFeedWithEntries feedWrapper = new ODataFeedWithEntries(feed); if (itemsStack.Count > 0) { ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek(); Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link."); Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child."); parentNavigationLink.NestedItems.Add(feedWrapper); } else { topLevelItem = feedWrapper; } itemsStack.Push(feedWrapper); break; case ODataReaderState.FeedEnd: Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The feed which is ending should be on the top of the items stack."); itemsStack.Pop(); break; case ODataReaderState.EntityReferenceLink: ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)reader.Item; Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null."); ODataEntityReferenceLinkBase entityReferenceLinkWrapper = new ODataEntityReferenceLinkBase(entityReferenceLink); Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item."); { ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek(); parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper); } break; default: Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state."); break; } } Contract.Assert(reader.State == ODataReaderState.Completed, "We should have consumed all of the input by now."); Contract.Assert(topLevelItem != null, "A top level entry or feed should have been read by now."); return(topLevelItem); }
protected HttpResponseMessage GenerateAsyncOperationScheduled() { var operations = new ODataFeed<AsyncOperation>(); operations.Feed = new List<AsyncOperation> { new AsyncOperation { BatchID = GetId(10), BatchSourceID = GetId(), BatchProgress = 0, BatchState = AsyncOperationState.Scheduled } }; return new HttpResponseMessage(HttpStatusCode.Accepted) { Content = new StringContent(JsonConvert.SerializeObject(operations), Encoding.UTF8, "application/json") }; }
private void Read(Lazy <ODataReader> lazyReader) { foreach (var state in this.expectedStates) { lazyReader.Value.Read(); ExceptionUtilities.Assert(lazyReader.Value.State == state, "Expected %1, Found %2", state, lazyReader.Value.State); switch (state) { case ODataReaderState.FeedStart: if (readItems.Count > 0) { ODataNavigationLink navLink = (ODataNavigationLink)readItems.Peek(); var annotation = navLink.GetAnnotation <ODataNavigationLinkExpandedItemObjectModelAnnotation>(); if (annotation == null) { annotation = new ODataNavigationLinkExpandedItemObjectModelAnnotation(); navLink.SetAnnotation(annotation); } annotation.ExpandedItem = lazyReader.Value.Item; } readItems.Push(lazyReader.Value.Item); break; case ODataReaderState.EntryStart: var currentEntry = (ODataEntry)lazyReader.Value.Item; if (readItems.Count > 0) { ODataFeed feed = readItems.Peek() as ODataFeed; if (feed != null) { var annotation = feed.GetAnnotation <ODataFeedEntriesObjectModelAnnotation>(); if (annotation == null) { annotation = new ODataFeedEntriesObjectModelAnnotation(); feed.SetAnnotation(annotation); } annotation.Add((ODataEntry)lazyReader.Value.Item); } else { ODataNavigationLink navLink = (ODataNavigationLink)readItems.Peek(); var annotation = navLink.GetAnnotation <ODataNavigationLinkExpandedItemObjectModelAnnotation>(); if (annotation == null) { annotation = new ODataNavigationLinkExpandedItemObjectModelAnnotation(); navLink.SetAnnotation(annotation); } annotation.ExpandedItem = currentEntry; } } readItems.Push(currentEntry); break; case ODataReaderState.NavigationLinkStart: ODataEntry entry = (ODataEntry)readItems.Peek(); var navLinksAnnotation = entry.GetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>(); if (navLinksAnnotation == null) { navLinksAnnotation = new ODataEntryNavigationLinksObjectModelAnnotation(); entry.SetAnnotation(navLinksAnnotation); } navLinksAnnotation.Add((ODataNavigationLink)lazyReader.Value.Item, entry.Properties.Count() + navLinksAnnotation.Count); readItems.Push(lazyReader.Value.Item); break; case ODataReaderState.EntryEnd: case ODataReaderState.FeedEnd: case ODataReaderState.NavigationLinkEnd: if (readItems.Count() > 1) { readItems.Pop(); } break; } } this.expectedStates.Clear(); }
public void WritingNestedInlinecountTest() { ODataFeed feed = new ODataFeed { Count = 1 }; ODataItem[] itemsToWrite = new ODataItem[] { new ODataFeed(), this.entryWithOnlyData1, this.containedCollectionNavLink, feed }; string resourcePath = "EntitySet"; string result = this.GetWriterOutputForContentTypeAndKnobValue("application/json;odata.metadata=minimal", true, itemsToWrite, Model, EntitySet, EntityType, null, null, resourcePath); string expectedPayload = "{" + "\"@odata.context\":\"http://example.org/odata.svc/$metadata#EntitySet\"," + "\"value\":[" + "{" + "\"ID\":101,\"Name\":\"Alice\"," + "\"[email protected]\":\"http://example.org/odata.svc/$metadata#EntitySet(101)/ContainedCollectionNavProp\"," + "\"[email protected]\":\"http://example.org/odata.svc/navigation\"," + "\"[email protected]\":1," + "\"ContainedCollectionNavProp\":[]" + "}" + "]" + "}"; result.Should().Be(expectedPayload); }
private void WriteTopLevelFeed(ODataMessageWriterTestWrapper messageWriter, ODataMessageReaderTestWrapper messageReader, ODataFeed feed) { var feedWriter = messageWriter.CreateODataFeedWriter(); Lazy <ODataReader> lazyReader = new Lazy <ODataReader>(() => messageReader.CreateODataFeedReader()); this.WriteFeed(feedWriter, lazyReader, feed); }
/// <summary> /// Creates a new instance of ODataAction or ODataFunction for the <paramref name="metadataReferencePropertyName"/>. /// </summary> /// <param name="feed">The feed to add the action or function .</param> /// <param name="metadataReferencePropertyName">The name of the metadata reference property being read.</param> /// <returns>A new instance of ODataAction or ODataFunction for the <paramref name="metadataReferencePropertyName"/>.</returns> private ODataOperation CreateODataOperationAndAddToFeed(ODataFeed feed, string metadataReferencePropertyName) { string fullyQualifiedOperationName = ODataJsonLightUtils.GetUriFragmentFromMetadataReferencePropertyName(this.ContextUriParseResult.MetadataDocumentUri, metadataReferencePropertyName); IEdmOperation firstActionOrFunction = this.JsonLightInputContext.Model.ResolveOperations(fullyQualifiedOperationName).FirstOrDefault(); bool isAction; if (firstActionOrFunction == null) { // Ignore the unknown function/action. return null; } var operation = ODataJsonLightUtils.CreateODataOperation(this.ContextUriParseResult.MetadataDocumentUri, metadataReferencePropertyName, firstActionOrFunction, out isAction); if (isAction) { feed.AddAction((ODataAction)operation); } else { feed.AddFunction((ODataFunction)operation); } return operation; }
/// <summary> /// Initializes a new instance of <see cref="ODataFeedWithEntries"/>. /// </summary> /// <param name="item">The wrapped item.</param> public ODataFeedWithEntries(ODataFeed item) : base(item) { Entries = new List <ODataEntryWithNavigationLinks>(); }
/// <summary> /// Reads expanded feed navigation link. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="navigationProperty">The navigation property for which to read the expanded link.</param> /// <returns>The navigation link info for the expanded link read.</returns> /// <remarks> /// This method doesn't move the reader. /// </remarks> private static ODataJsonLightReaderNavigationLinkInfo ReadExpandedFeedNavigationLink(IODataJsonLightReaderEntryState entryState, IEdmNavigationProperty navigationProperty) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = navigationProperty.Name, IsCollection = true }; ODataFeed expandedFeed = new ODataFeed(); Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(navigationLink.Name); if (propertyAnnotations != null) { foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations) { switch (propertyAnnotation.Key) { case ODataAnnotationNames.ODataNavigationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.navigationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.Url = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataAssociationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.associationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.AssociationLinkUrl = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataNextLink: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.nextLink annotation should have been parsed as a non-null Uri."); expandedFeed.NextPageLink = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataCount: Debug.Assert(propertyAnnotation.Value is long && propertyAnnotation.Value != null, "The odata.count annotation should have been parsed as a non-null long."); expandedFeed.Count = (long?)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataContext: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.context annotation should have been parsed as a non-null Uri."); navigationLink.ContextUrl = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataDeltaLink: // Delta links are not supported on expanded feeds. default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedExpandedCollectionNavigationLinkPropertyAnnotation(navigationLink.Name, propertyAnnotation.Key)); } } } return ODataJsonLightReaderNavigationLinkInfo.CreateExpandedFeedLinkInfo(navigationLink, navigationProperty, expandedFeed); }
/// <summary> /// Create the <see cref="ODataFeed"/> to be written for the given feed instance. /// </summary> /// <param name="feedInstance">The instance representing the feed being written.</param> /// <param name="feedType">The EDM type of the feed being written.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataFeed"/> object.</returns> public virtual ODataFeed CreateODataFeed(IEnumerable feedInstance, IEdmCollectionTypeReference feedType, ODataSerializerContext writeContext) { ODataFeed feed = new ODataFeed(); if (writeContext.EntitySet != null) { IEdmModel model = writeContext.Model; EntitySetLinkBuilderAnnotation linkBuilder = model.GetEntitySetLinkBuilder(writeContext.EntitySet); FeedContext feedContext = new FeedContext { Request = writeContext.Request, RequestContext = writeContext.RequestContext, EntitySet = writeContext.EntitySet, Url = writeContext.Url, FeedInstance = feedInstance }; Uri feedSelfLink = linkBuilder.BuildFeedSelfLink(feedContext); if (feedSelfLink != null) { feed.SetAnnotation(new AtomFeedMetadata() { SelfLink = new AtomLinkMetadata() { Relation = "self", Href = feedSelfLink } }); } } // TODO: Bug 467590: remove the hardcoded feed id. Get support for it from the model builder ? feed.Id = "http://schemas.datacontract.org/2004/07/" + feedType.FullName(); if (writeContext.ExpandedEntity == null) { // If we have more OData format specific information apply it now, only if we are the root feed. PageResult odataFeedAnnotations = feedInstance as PageResult; if (odataFeedAnnotations != null) { feed.Count = odataFeedAnnotations.Count; feed.NextPageLink = odataFeedAnnotations.NextPageLink; } else if (writeContext.Request != null) { feed.NextPageLink = writeContext.Request.ODataProperties().NextLink; long?inlineCount = writeContext.Request.ODataProperties().TotalCount; if (inlineCount.HasValue) { feed.Count = inlineCount.Value; } } } else { // nested feed ITruncatedCollection truncatedCollection = feedInstance as ITruncatedCollection; if (truncatedCollection != null && truncatedCollection.IsTruncated) { feed.NextPageLink = GetNestedNextPageLink(writeContext, truncatedCollection.PageSize); } } return(feed); }
/// <summary> /// Writes the next page link for a feed. /// </summary> /// <param name="feed">The feed to write the next page link for.</param> internal void WriteFeedNextPageLink(ODataFeed feed) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(feed != null, "feed != null"); Uri nextPageLink = feed.NextPageLink; if (nextPageLink != null) { // <atom:link rel="next" href="next-page-link" /> AtomFeedMetadata feedMetadata = feed.GetAnnotation<AtomFeedMetadata>(); AtomLinkMetadata mergedLink = ODataAtomWriterMetadataUtils.MergeLinkMetadata( feedMetadata == null ? null : feedMetadata.NextPageLink, AtomConstants.AtomNextRelationAttributeValue, nextPageLink, null, /*title*/ null /*mediaType*/); this.atomFeedMetadataSerializer.WriteAtomLink(mergedLink, null); } }
public override void WriteStart(ODataFeed feed) { }
protected override ODataWriterCore.FeedScope CreateFeedScope(ODataFeed feed, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { throw new NotImplementedException(); }
public override Task WriteStartAsync(ODataFeed feed) { throw new InternalTestFailureException("Should not hit this code"); }