/// <summary> /// Writes a set of links (Uris) in response to a $ref query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.WriteTopLevelPayload( () => this.WriteEntityReferenceLinksImplementation(entityReferenceLinks)); }
/// <summary> /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.WriteTopLevelPayload( () => this.WriteEntityReferenceLinksImplementation(entityReferenceLinks, this.Version >= ODataVersion.V2 && this.WritingResponse)); }
/// <summary> /// Writes a set of links (Uris) in response to a $ref query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks entityReferenceLinks) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); bool wroteNextLink = false; // { this.JsonWriter.StartObjectScope(); // "@odata.context": ... this.WriteContextUriProperty(ODataPayloadKind.EntityReferenceLinks); if (entityReferenceLinks.Count.HasValue) { // We try to write the count property at the top of the payload if one is available. // "@odata.count": ... this.WriteCountAnnotation(entityReferenceLinks.Count.Value); } if (entityReferenceLinks.NextPageLink != null) { // We try to write the next link at the top of the payload if one is available. If not, we try again at the end. wroteNextLink = true; // "@odata.next": ... this.WriteNextLinkAnnotation(entityReferenceLinks.NextPageLink); } this.InstanceAnnotationWriter.WriteInstanceAnnotations(entityReferenceLinks.InstanceAnnotations); // "value": this.JsonWriter.WriteValuePropertyName(); // "[": this.JsonWriter.StartArrayScope(); IEnumerable<ODataEntityReferenceLink> entityReferenceLinksEnumerable = entityReferenceLinks.Links; if (entityReferenceLinksEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinksEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLinkImplementation(entityReferenceLink, /* isTopLevel */ false); } } // "]" this.JsonWriter.EndArrayScope(); if (!wroteNextLink && entityReferenceLinks.NextPageLink != null) { // "@odata.next": ... this.WriteNextLinkAnnotation(entityReferenceLinks.NextPageLink); } // "}" this.JsonWriter.EndObjectScope(); }
/// <summary> /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> /// <param name="includeResultsWrapper">true if the 'results' wrapper should be included into the payload; otherwise false.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks entityReferenceLinks, bool includeResultsWrapper) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); if (includeResultsWrapper) { // { this.JsonWriter.StartObjectScope(); } if (entityReferenceLinks.Count.HasValue) { Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a count is specified."); this.JsonWriter.WriteName(JsonConstants.ODataCountName); this.JsonWriter.WriteValue(entityReferenceLinks.Count.Value); } if (includeResultsWrapper) { // "results": this.JsonWriter.WriteDataArrayName(); } this.JsonWriter.StartArrayScope(); IEnumerable<ODataEntityReferenceLink> entityReferenceLinksEnumerable = entityReferenceLinks.Links; if (entityReferenceLinksEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinksEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLinkImplementation(entityReferenceLink); } } this.JsonWriter.EndArrayScope(); if (entityReferenceLinks.NextPageLink != null) { // "__next": ... Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a next page link is specified."); this.JsonWriter.WriteName(JsonConstants.ODataNextLinkName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(entityReferenceLinks.NextPageLink)); } if (includeResultsWrapper) { this.JsonWriter.EndObjectScope(); } }
public void ShouldBeAbleToSetLinksReferenceLinks() { ODataEntityReferenceLink link = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link } }; referencelinks.Should().NotBeNull(); referencelinks.Links.Should().NotBeNull(); referencelinks.Links.Count().Should().Be(1); }
/// <summary> /// Writes a set of links (Uris) in response to a $ref query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.WritePayloadStart(); // COMPAT 25: Should $link payloads use the default 'd' namespace prefix for data service elements (instead of no prefix)? // <feed> ... this.XmlWriter.WriteStartElement(string.Empty, AtomConstants.AtomFeedElementName, AtomConstants.AtomNamespace); // xmlns:metadata= this.XmlWriter.WriteAttributeString(AtomConstants.XmlnsNamespacePrefix, AtomConstants.ODataMetadataNamespacePrefix, null, AtomConstants.ODataMetadataNamespace); // metadata:context this.WriteContextUriProperty(this.contextUriBuilder.BuildContextUri(ODataPayloadKind.EntityReferenceLinks)); if (entityReferenceLinks.Count.HasValue) { // <m:count> this.WriteCount(entityReferenceLinks.Count.Value); } IEnumerable<ODataEntityReferenceLink> entityReferenceLinkEnumerable = entityReferenceLinks.Links; if (entityReferenceLinkEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinkEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLink(entityReferenceLink, false); } } if (entityReferenceLinks.NextPageLink != null) { // <d:next> string nextLink = this.UriToUrlAttributeValue(entityReferenceLinks.NextPageLink); this.XmlWriter.WriteElementString(string.Empty, AtomConstants.ODataNextLinkElementName, AtomConstants.ODataNamespace, nextLink); } // </feed> this.XmlWriter.WriteEndElement(); this.WritePayloadEnd(); }
/// <summary> /// Read a set of top-level entity reference links. /// </summary> /// <returns>An <see cref="ODataEntityReferenceLinks"/> representing the read links.</returns> internal ODataEntityReferenceLinks ReadEntityReferenceLinks() { DebugUtils.CheckNoExternalCallers(); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet."); this.JsonReader.AssertNotBuffering(); // Set to true if the entity reference links are expected to have the 'results' wrapper. // Entity reference links are only expected to have a results wrapper if // (a) the protocol version is >= 2 AND // (b) we are reading a response // NOTE: OIPI does not specify a format for >= v2 entity reference links in requests; we thus use the v1 format and consequently do not expect a result wrapper. bool isResultsWrapperExpected = this.Version >= ODataVersion.V2 && this.ReadingResponse; ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask propertiesFoundBitField = ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.None; ODataEntityReferenceLinks entityReferenceLinks = new ODataEntityReferenceLinks(); // Read the response wrapper "d" if expected. this.ReadPayloadStart(false /*isReadingNestedPayload*/); if (isResultsWrapperExpected) { // Read the start object of the results wrapper object this.JsonReader.ReadStartObject(); bool foundResultsProperty = this.ReadEntityReferenceLinkProperties(entityReferenceLinks, ref propertiesFoundBitField); if (!foundResultsProperty) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksResultsPropertyNotFound); } } // Read the start of the content array of the links this.JsonReader.ReadStartArray(); List<ODataEntityReferenceLink> links = new List<ODataEntityReferenceLink>(); while (this.JsonReader.NodeType != JsonNodeType.EndArray) { // read another link ODataEntityReferenceLink entityReferenceLink = this.ReadSingleEntityReferenceLink(); links.Add(entityReferenceLink); } // Read over the end object - note that this might be the last node in the input (in case there's no response wrapper) this.JsonReader.ReadEndArray(); if (isResultsWrapperExpected) { this.ReadEntityReferenceLinkProperties(entityReferenceLinks, ref propertiesFoundBitField); // Read the end object of the results wrapper object this.JsonReader.ReadEndObject(); } entityReferenceLinks.Links = new ReadOnlyEnumerable<ODataEntityReferenceLink>(links); // Read the end of the response wrapper "d" if expected. this.ReadPayloadEnd(false /*isReadingNestedPayload*/); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput"); this.JsonReader.AssertNotBuffering(); return entityReferenceLinks; }
private static string WriteToString(ODataEntityReferenceLinks referencelinks, bool writingResponse = true, bool synchronous = true) { MemoryStream stream = new MemoryStream(); var outputContext = CreateJsonLightOutputContext(stream, writingResponse, synchronous); outputContext.WriteEntityReferenceLinks(referencelinks); stream.Seek(0, SeekOrigin.Begin); return (new StreamReader(stream)).ReadToEnd(); }
public void TheNewEntityReferenceLinksShouldNotBeNull() { ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks(); referencelinks.Should().NotBeNull(); referencelinks.Links.Should().BeNull(); }
private static void SameEntityReferenceLinks(ODataEntityReferenceLinks links1, ODataEntityReferenceLinks links2) { links1.Should().NotBeNull(); links2.Should().NotBeNull(); links1.Links.Should().NotBeNull(); links2.Links.Should().NotBeNull(); links1.Links.Count().Should().Equals(links2.Links.Count()); for (var i = 0; i < links1.Links.Count(); ++i) { SameEntityReferenceLink(links1.Links.ElementAt(i), links2.Links.ElementAt(i)); } SameInstanceAnnotations(links1.InstanceAnnotations, links2.InstanceAnnotations); }
/// <summary> /// Reads the entity reference link instance annotations. /// </summary> /// <param name="links">The <see cref="ODataEntityReferenceLinks"/> to read the annotations for.</param> /// <param name="propertyAndAnnotationCollector">The duplicate property names checker for the entity reference links scope.</param> /// <param name="forLinksStart">true when parsing the instance annotations before the 'value' property; /// false when parsing the instance annotations after the 'value' property.</param> /// <remarks> /// Pre-Condition: JsonNodeType.Property The first property in the payload (or the first property after the context URI in responses) /// JsonNodeType.EndObject The end of the entity reference links object /// Post-Condition: JsonNodeType.EndObject When the end of the entity reference links object is reached /// Any The first node of the value of the 'url' property (if found) /// </remarks> private void ReadEntityReferenceLinksAnnotations(ODataEntityReferenceLinks links, PropertyAndAnnotationCollector propertyAndAnnotationCollector, bool forLinksStart) { Debug.Assert(links != null, "links != null"); Debug.Assert(propertyAndAnnotationCollector != null, "propertyAndAnnotationCollector != null"); this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); this.JsonReader.AssertNotBuffering(); while (this.JsonReader.NodeType == JsonNodeType.Property) { // OData property annotations are not supported on entity reference links. Func <string, object> propertyAnnotationValueReader = annotationName => { throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLinks); }; bool foundValueProperty = false; this.ProcessProperty( propertyAndAnnotationCollector, propertyAnnotationValueReader, (propertyParseResult, propertyName) => { switch (propertyParseResult) { case PropertyParsingResult.ODataInstanceAnnotation: if (string.CompareOrdinal(ODataAnnotationNames.ODataNextLink, propertyName) == 0) { this.ReadEntityReferenceLinksNextLinkAnnotationValue(links); } else if (string.CompareOrdinal(ODataAnnotationNames.ODataCount, propertyName) == 0) { this.ReadEntityReferenceCountAnnotationValue(links); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName)); } break; case PropertyParsingResult.CustomInstanceAnnotation: Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); this.AssertJsonCondition(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, JsonNodeType.StartArray); ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName); Debug.Assert( !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName), "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(propertyName) -- otherwise we should have already skipped the custom annotation and won't see it here."); object annotationValue = this.ReadCustomInstanceAnnotationValue(propertyAndAnnotationCollector, propertyName); links.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, annotationValue.ToODataValue())); break; case PropertyParsingResult.PropertyWithValue: if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) != 0) { // We did not find a supported link collection property; fail. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidEntityReferenceLinksPropertyFound(propertyName, JsonLightConstants.ODataValuePropertyName)); } // We found the link collection property and are done parsing property annotations; foundValueProperty = true; break; case PropertyParsingResult.PropertyWithoutValue: // If we find a property without a value it means that we did not find the entity reference links property (yet) // but an invalid property annotation throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyAnnotationInEntityReferenceLinks(propertyName)); case PropertyParsingResult.EndOfObject: break; case PropertyParsingResult.MetadataReferenceProperty: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName)); default: throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadEntityReferenceLinksAnnotations)); } }); if (foundValueProperty) { return; } } if (forLinksStart) { // We did not find the 'value' property. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksPropertyNotFound(JsonLightConstants.ODataValuePropertyName)); } this.AssertJsonCondition(JsonNodeType.EndObject); }
internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { base.WriteTopLevelPayload(() => this.WriteEntityReferenceLinksImplementation(entityReferenceLinks, (this.Version >= ODataVersion.V2) && this.WritingResponse)); }
/// <summary> /// Visits an item in the object model. /// </summary> /// <param name="objectModelItem">The item to visit.</param> public virtual T Visit(object objectModelItem) { ODataFeed feed = objectModelItem as ODataFeed; if (feed != null) { return(this.VisitFeed(feed)); } ODataEntry entry = objectModelItem as ODataEntry; if (entry != null) { return(this.VisitEntry(entry)); } ODataProperty property = objectModelItem as ODataProperty; if (property != null) { return(this.VisitProperty(property)); } ODataNavigationLink navigationLink = objectModelItem as ODataNavigationLink; if (navigationLink != null) { return(this.VisitNavigationLink(navigationLink)); } ODataComplexValue complexValue = objectModelItem as ODataComplexValue; if (complexValue != null) { return(this.VisitComplexValue(complexValue)); } ODataCollectionValue collection = objectModelItem as ODataCollectionValue; if (collection != null) { return(this.VisitCollectionValue(collection)); } ODataStreamReferenceValue streamReferenceValue = objectModelItem as ODataStreamReferenceValue; if (streamReferenceValue != null) { return(this.VisitStreamReferenceValue(streamReferenceValue)); } ODataCollectionStart collectionStart = objectModelItem as ODataCollectionStart; if (collectionStart != null) { return(this.VisitCollectionStart(collectionStart)); } ODataServiceDocument serviceDocument = objectModelItem as ODataServiceDocument; if (serviceDocument != null) { return(this.VisitWorkspace(serviceDocument)); } ODataEntitySetInfo entitySetInfo = objectModelItem as ODataEntitySetInfo; if (entitySetInfo != null) { return(this.VisitResourceCollection(entitySetInfo)); } ODataError error = objectModelItem as ODataError; if (error != null) { return(this.VisitError(error)); } ODataInnerError innerError = objectModelItem as ODataInnerError; if (innerError != null) { return(this.VisitInnerError(innerError)); } ODataEntityReferenceLinks entityReferenceLinks = objectModelItem as ODataEntityReferenceLinks; if (entityReferenceLinks != null) { return(this.VisitEntityReferenceLinks(entityReferenceLinks)); } ODataEntityReferenceLink entityReferenceLink = objectModelItem as ODataEntityReferenceLink; if (entityReferenceLink != null) { return(this.VisitEntityReferenceLink(entityReferenceLink)); } ODataAction action = objectModelItem as ODataAction; if (action != null) { return(this.VisitODataOperation(action)); } ODataFunction function = objectModelItem as ODataFunction; if (function != null) { return(this.VisitODataOperation(function)); } ODataParameters parameters = objectModelItem as ODataParameters; if (parameters != null) { return(this.VisitParameters(parameters)); } ODataBatch batch = objectModelItem as ODataBatch; if (batch != null) { return(this.VisitBatch(batch)); } if (objectModelItem == null || objectModelItem.GetType().IsValueType || objectModelItem is string || objectModelItem is byte[] || objectModelItem is ISpatial) { return(this.VisitPrimitiveValue(objectModelItem)); } return(this.VisitUnsupportedValue(objectModelItem)); }
/// <summary> /// Read a set of top-level entity reference links. /// </summary> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use for the top-level scope.</param> /// <returns>An <see cref="ODataEntityReferenceLinks"/> representing the read links.</returns> private ODataEntityReferenceLinks ReadEntityReferenceLinksImplementation(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); ODataEntityReferenceLinks entityReferenceLinks = new ODataEntityReferenceLinks(); this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/true); // Read the start of the content array of the links this.JsonReader.ReadStartArray(); List<ODataEntityReferenceLink> links = new List<ODataEntityReferenceLink>(); DuplicatePropertyNamesChecker linkDuplicatePropertyNamesChecker = this.JsonLightInputContext.CreateDuplicatePropertyNamesChecker(); while (this.JsonReader.NodeType != JsonNodeType.EndArray) { // read another link ODataEntityReferenceLink entityReferenceLink = this.ReadSingleEntityReferenceLink(linkDuplicatePropertyNamesChecker, /*topLevel*/false); links.Add(entityReferenceLink); linkDuplicatePropertyNamesChecker.Clear(); } this.JsonReader.ReadEndArray(); this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/false); this.JsonReader.ReadEndObject(); entityReferenceLinks.Links = new ReadOnlyEnumerable<ODataEntityReferenceLink>(links); return entityReferenceLinks; }
/// <summary> /// Reads the entity reference link instance annotations. /// </summary> /// <param name="links">The <see cref="ODataEntityReferenceLinks"/> to read the annotations for.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the entity reference links scope.</param> /// <param name="forLinksStart">true when parsing the instance annotations before the 'value' property; /// false when parsing the instance annotations after the 'value' property.</param> /// <remarks> /// Pre-Condition: JsonNodeType.Property The first property in the payload (or the first property after the context URI in responses) /// JsonNodeType.EndObject The end of the entity reference links object /// Post-Condition: JsonNodeType.EndObject When the end of the entity reference links object is reached /// Any The first node of the value of the 'url' property (if found) /// </remarks> private void ReadEntityReferenceLinksAnnotations(ODataEntityReferenceLinks links, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool forLinksStart) { Debug.Assert(links != null, "links != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); this.JsonReader.AssertNotBuffering(); while (this.JsonReader.NodeType == JsonNodeType.Property) { // OData property annotations are not supported on entity reference links. Func<string, object> propertyAnnotationValueReader = annotationName => { throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLinks); }; bool foundValueProperty = false; this.ProcessProperty( duplicatePropertyNamesChecker, propertyAnnotationValueReader, (propertyParseResult, propertyName) => { switch (propertyParseResult) { case PropertyParsingResult.ODataInstanceAnnotation: if (string.CompareOrdinal(ODataAnnotationNames.ODataNextLink, propertyName) == 0) { this.ReadEntityReferenceLinksNextLinkAnnotationValue(links); } else if (string.CompareOrdinal(ODataAnnotationNames.ODataCount, propertyName) == 0) { this.ReadEntityReferenceCountAnnotationValue(links); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName)); } break; case PropertyParsingResult.CustomInstanceAnnotation: this.JsonReader.SkipValue(); break; case PropertyParsingResult.PropertyWithValue: if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) != 0) { // We did not find a supported link collection property; fail. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidEntityReferenceLinksPropertyFound(propertyName, JsonLightConstants.ODataValuePropertyName)); } // We found the link collection property and are done parsing property annotations; foundValueProperty = true; break; case PropertyParsingResult.PropertyWithoutValue: // If we find a property without a value it means that we did not find the entity reference links property (yet) // but an invalid property annotation throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyAnnotationInEntityReferenceLinks(propertyName)); case PropertyParsingResult.EndOfObject: break; case PropertyParsingResult.MetadataReferenceProperty: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName)); default: throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadEntityReferenceLinksAnnotations)); } }); if (foundValueProperty) { return; } } if (forLinksStart) { // We did not find the 'value' property. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksPropertyNotFound(JsonLightConstants.ODataValuePropertyName)); } this.AssertJsonCondition(JsonNodeType.EndObject); }
private void WriteEntityReferenceLinks(ODataMessageWriterTestWrapper messageWriter, ODataEntityReferenceLinks referenceLinks) { messageWriter.WriteEntityReferenceLinks(referenceLinks); }
/// <summary> /// Visits an entity reference link collection. /// </summary> /// <param name="entityReferenceLinks">The entity reference link collection to visit.</param> protected override void VisitEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { this.ValidateUri(entityReferenceLinks.NextPageLink); base.VisitEntityReferenceLinks(entityReferenceLinks); }
/// <summary> /// Read a set of top-level entity reference links. /// </summary> /// <returns>An <see cref="ODataEntityReferenceLinks"/> representing the read links.</returns> internal ODataEntityReferenceLinks ReadEntityReferenceLinks() { DebugUtils.CheckNoExternalCallers(); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet."); this.JsonReader.AssertNotBuffering(); // Set to true if the entity reference links are expected to have the 'results' wrapper. // Entity reference links are only expected to have a results wrapper if // (a) the protocol version is >= 2 AND // (b) we are reading a response // NOTE: OIPI does not specify a format for >= v2 entity reference links in requests; we thus use the v1 format and consequently do not expect a result wrapper. bool isResultsWrapperExpected = this.Version >= ODataVersion.V2 && this.ReadingResponse; ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask propertiesFoundBitField = ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.None; ODataEntityReferenceLinks entityReferenceLinks = new ODataEntityReferenceLinks(); // Read the response wrapper "d" if expected. this.ReadPayloadStart(false /*isReadingNestedPayload*/); if (isResultsWrapperExpected) { // Read the start object of the results wrapper object this.JsonReader.ReadStartObject(); bool foundResultsProperty = this.ReadEntityReferenceLinkProperties(entityReferenceLinks, ref propertiesFoundBitField); if (!foundResultsProperty) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksResultsPropertyNotFound); } } // Read the start of the content array of the links this.JsonReader.ReadStartArray(); List <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>(); while (this.JsonReader.NodeType != JsonNodeType.EndArray) { // read another link ODataEntityReferenceLink entityReferenceLink = this.ReadSingleEntityReferenceLink(); links.Add(entityReferenceLink); } // Read over the end object - note that this might be the last node in the input (in case there's no response wrapper) this.JsonReader.ReadEndArray(); if (isResultsWrapperExpected) { this.ReadEntityReferenceLinkProperties(entityReferenceLinks, ref propertiesFoundBitField); // Read the end object of the results wrapper object this.JsonReader.ReadEndObject(); } entityReferenceLinks.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(links); // Read the end of the response wrapper "d" if expected. this.ReadPayloadEnd(false /*isReadingNestedPayload*/); Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput"); this.JsonReader.AssertNotBuffering(); return(entityReferenceLinks); }
internal override void WriteEntityReferenceLinks(ODataEntityReferenceLinks links) { this.WriteEntityReferenceLinksImplementation(links); this.Flush(); }
/// <summary> /// Asynchronously writes a set of links (Uris) in response to a $ref query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> private async Task WriteEntityReferenceLinksImplementationAsync(ODataEntityReferenceLinks entityReferenceLinks) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); bool wroteNextLink = false; // { await this.AsynchronousJsonWriter.StartObjectScopeAsync() .ConfigureAwait(false); // "@odata.context": ... await this.WriteContextUriPropertyAsync(ODataPayloadKind.EntityReferenceLinks) .ConfigureAwait(false); if (entityReferenceLinks.Count.HasValue) { // We try to write the count property at the top of the payload if one is available. // "@odata.count": ... await this.WriteCountAnnotationAsync(entityReferenceLinks.Count.Value) .ConfigureAwait(false); } if (entityReferenceLinks.NextPageLink != null) { // We try to write the next link at the top of the payload if one is available. If not, we try again at the end. wroteNextLink = true; // "@odata.next": ... await this.WriteNextLinkAnnotationAsync(entityReferenceLinks.NextPageLink) .ConfigureAwait(false); } this.InstanceAnnotationWriter.WriteInstanceAnnotations(entityReferenceLinks.InstanceAnnotations); // "value": await this.AsynchronousJsonWriter.WriteValuePropertyNameAsync() .ConfigureAwait(false); // "[": await this.AsynchronousJsonWriter.StartArrayScopeAsync() .ConfigureAwait(false); IEnumerable <ODataEntityReferenceLink> entityReferenceLinksEnumerable = entityReferenceLinks.Links; if (entityReferenceLinksEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinksEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); await this.WriteEntityReferenceLinkImplementationAsync(entityReferenceLink, /* isTopLevel */ false) .ConfigureAwait(false); } } // "]" await this.AsynchronousJsonWriter.EndArrayScopeAsync() .ConfigureAwait(false); if (!wroteNextLink && entityReferenceLinks.NextPageLink != null) { // "@odata.next": ... await this.WriteNextLinkAnnotationAsync(entityReferenceLinks.NextPageLink) .ConfigureAwait(false); } // "}" await this.AsynchronousJsonWriter.EndObjectScopeAsync() .ConfigureAwait(false); }
public void ShouldWriteForEntityReferenceLinksWithMultpleLinks() { ODataEntityReferenceLink link1 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link1.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLink link2 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(2)") }; link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.unknown", new ODataPrimitiveValue(123))); link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(456))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link1, link2 } }; string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true},{\"@odata.id\":\"http://host/Customers(2)\",\"@TestNamespace.unknown\":123,\"@custom.annotation\":456}]}"; WriteAndValidate(referencelinks, expectedPayload, writingResponse: false); WriteAndValidate(referencelinks, expectedPayload, writingResponse: true); }
/// <summary> /// Reads the odata.nextlink value of an entity reference links nextlink annotation. /// </summary> /// <param name="links">The entity reference links to read the next link value for; the value of the nextlink will be assigned to this instance.</param> /// <remarks> /// Pre-Condition: JsonNodeType.PrimitiveValue The value of the instance annotation /// Post-Condition: JsonNodeType.EndObject The end of the entity reference links object /// JsonNodeType.Property The next property after the instance annotation /// </remarks> private void ReadEntityReferenceLinksNextLinkAnnotationValue(ODataEntityReferenceLinks links) { Debug.Assert(links != null, "links != null"); this.AssertJsonCondition(JsonNodeType.PrimitiveValue); Uri nextPageUri = this.ReadAndValidateAnnotationStringValueAsUri(ODataAnnotationNames.ODataNextLink); Debug.Assert(links.NextPageLink == null, "We should have checked for duplicates already."); links.NextPageLink = nextPageUri; }
public static string ConvertToUriLiteral(object value, ODataVersion version, IEdmModel model) { if (value == null) { value = new ODataNullValue(); } if (model == null) { model = Microsoft.OData.Edm.Library.EdmCoreModel.Instance; } ODataNullValue nullValue = value as ODataNullValue; if (nullValue != null) { return(ExpressionConstants.KeywordNull); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { return(ODataUriConversionUtils.ConvertToUriCollectionLiteral(collectionValue, model, version)); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { return(ODataUriConversionUtils.ConvertToUriComplexLiteral(complexValue, model, version)); } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { return(ODataUriConversionUtils.ConvertToUriEnumLiteral(enumValue, version)); } ODataEntry entry = value as ODataEntry; if (entry != null) { return(ODataUriConversionUtils.ConvertToUriEntityLiteral(entry, model)); } ODataEntityReferenceLink link = value as ODataEntityReferenceLink; if (link != null) { return(ODataUriConversionUtils.ConvertToUriEntityReferenceLiteral(link, model)); } ODataEntityReferenceLinks links = value as ODataEntityReferenceLinks; if (links != null) { return(ODataUriConversionUtils.ConvertToUriEntityReferencesLiteral(links, model)); } var list = value as IEnumerable <ODataEntry>; if (list != null) { return(ODataUriConversionUtils.ConvertToUriEntitiesLiteral(list, model)); } // Try to convert uints to their underlying type first according to the model. value = model.ConvertToUnderlyingTypeIfUIntValue(value); return(ODataUriConversionUtils.ConvertToUriPrimitiveLiteral(value, version)); }
/// <summary> /// Reads the value of an entity reference links count annotation. /// </summary> /// <param name="links">The entity reference links to read the count value for; the value of the count will be assigned to this instance.</param> /// <remarks> /// Pre-Condition: JsonNodeType.PrimitiveValue The value of the instance annotation /// Post-Condition: JsonNodeType.EndObject The end of the entity reference links object /// JsonNodeType.Property The next property after the instance annotation /// </remarks> private void ReadEntityReferenceCountAnnotationValue(ODataEntityReferenceLinks links) { Debug.Assert(links != null, "links != null"); this.AssertJsonCondition(JsonNodeType.PrimitiveValue); Debug.Assert(!links.Count.HasValue, "We should have checked for duplicates already."); links.Count = this.ReadAndValidateAnnotationAsLongForIeee754Compatible(ODataAnnotationNames.ODataCount); }
/// <summary> /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> /// <param name="entitySet">The entity set of the navigation property</param> /// <param name="navigationProperty">The navigation property for which the entity reference links are being written, or null if none is available.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks entityReferenceLinks, IEdmEntitySet entitySet, IEdmNavigationProperty navigationProperty) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); bool wroteNextLink = false; bool wroteCount = false; // { this.JsonWriter.StartObjectScope(); Uri metadataUri; if (this.metadataUriBuilder.TryBuildEntityReferenceLinksMetadataUri(entityReferenceLinks.SerializationInfo, entitySet, navigationProperty, out metadataUri)) { this.WriteMetadataUriProperty(metadataUri); } if (entityReferenceLinks.Count.HasValue) { // We try to write the count property at the top of the payload if one is available. If not, we try again at the end. wroteCount = true; // "odata.count": ... this.WriteCountAnnotation(entityReferenceLinks.Count.Value); } if (entityReferenceLinks.NextPageLink != null) { // We try to write the next link at the top of the payload if one is available. If not, we try again at the end. wroteNextLink = true; // "odata.next": ... this.WriteNextLinkAnnotation(entityReferenceLinks.NextPageLink); } // "value": this.JsonWriter.WriteValuePropertyName(); // "[": this.JsonWriter.StartArrayScope(); IEnumerable <ODataEntityReferenceLink> entityReferenceLinksEnumerable = entityReferenceLinks.Links; if (entityReferenceLinksEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinksEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLinkImplementation(entityReferenceLink, entitySet, /* navigationProperty */ null, /* isTopLevel */ false); } } // "]" this.JsonWriter.EndArrayScope(); if (!wroteCount && entityReferenceLinks.Count.HasValue) { // "odata.count": ... this.WriteCountAnnotation(entityReferenceLinks.Count.Value); } if (!wroteNextLink && entityReferenceLinks.NextPageLink != null) { // "odata.next": ... this.WriteNextLinkAnnotation(entityReferenceLinks.NextPageLink); } // "}" this.JsonWriter.EndObjectScope(); }
/// <summary> /// Parse the constant entity collection node. /// </summary> /// <param name="nodeIn">The input constant node.</param> /// <returns>The parsed object.</returns> private object ParseEntityCollection(ConstantNode nodeIn) { ODataMessageReaderSettings settings = new ODataMessageReaderSettings(); InMemoryMessage message = new InMemoryMessage() { Stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(nodeIn.LiteralText)), }; var entityType = ((nodeIn.TypeReference.Definition as IEdmCollectionType).ElementType as IEdmEntityTypeReference) .Definition as IEdmEntityType; object list = null; MethodInfo addMethod = null; using ( ODataMessageReader reader = new ODataMessageReader(message as IODataRequestMessage, settings, this.UriParser.Model)) { if (nodeIn.LiteralText.Contains("@odata.id")) { ODataEntityReferenceLinks referenceLinks = reader.ReadEntityReferenceLinks(); foreach (var referenceLink in referenceLinks.Links) { var queryContext = new QueryContext(this.UriParser.ServiceRoot, referenceLink.Url, this.DataSource.Model); var target = queryContext.ResolveQuery(this.DataSource); if (list == null) { // create the list. This would require the first type is not derived type. Type listType = typeof(List <>).MakeGenericType(target.GetType()); addMethod = listType.GetMethod("Add"); list = Activator.CreateInstance(listType); } addMethod.Invoke(list, new[] { target }); } return(list); } var feedReader = reader.CreateODataFeedReader( new EdmEntitySet(new EdmEntityContainer("NS", "Test"), "TestType", entityType), entityType); ODataEntry entry = null; while (feedReader.Read()) { if (feedReader.State == ODataReaderState.EntryEnd) { entry = feedReader.Item as ODataEntry; object item = ODataObjectModelConverter.ConvertPropertyValue(entry); if (list == null) { // create the list. This would require the first type is not derived type. var type = EdmClrTypeUtils.GetInstanceType(entry.TypeName); Type listType = typeof(List <>).MakeGenericType(type); addMethod = listType.GetMethod("Add"); list = Activator.CreateInstance(listType); } addMethod.Invoke(list, new[] { item }); } } return(list); } }
/// <summary> /// Visits an entity reference links instance. /// </summary> /// <param name="entityReferenceLinks">The entity reference links to visit.</param> protected override void VisitEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { this.ValidateEnumerable <ODataEntityReferenceLink>(entityReferenceLinks.Links, "ODataEntityReferenceLinks.Links"); base.VisitEntityReferenceLinks(entityReferenceLinks); }
public void WriteEntryWithWrongSerializationInfo() { foreach (var mimeType in this.testMimeTypes) { var settings = new ODataMessageWriterSettings(); settings.ODataUri = new ODataUri() { ServiceRoot = this.ServiceUri }; // wrong EntitySetName for entry var responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceWriter(); var entry = this.CreatePersonEntryWithoutSerializationInfo(); entry.SetSerializationInfo(new ODataResourceSerializationInfo() { NavigationSourceName = "Parsen", NavigationSourceEntityTypeName = NameSpace + "Person" }); odataWriter.WriteStart(entry); odataWriter.WriteEnd(); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains("\"PersonId\":-5")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Parsen/$entity")); Assert.IsTrue(result.Contains("Person(-5)\",\"PersonId\":-5")); } else { Assert.IsFalse(result.Contains("Person(-5)\",\"PersonId\":-5")); } } // wrong EntitySetName for feed responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceSetWriter(); var feed = this.CreatePersonFeed(); feed.SetSerializationInfo(new ODataResourceSerializationInfo() { NavigationSourceName = "Parsen", NavigationSourceEntityTypeName = NameSpace + "Person" }); var entry = this.CreatePersonEntryWithoutSerializationInfo(); odataWriter.WriteStart(feed); odataWriter.WriteStart(entry); odataWriter.WriteEnd(); odataWriter.WriteEnd(); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains("\"PersonId\":-5")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Parsen\"")); Assert.IsTrue(result.Contains("Person(-5)\",\"PersonId\":-5")); } else { Assert.IsFalse(result.Contains("Person(-5)\",\"PersonId\":-5")); } } // wrong complex collection type name responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceSetWriter(); var complexCollection = new ODataResourceSetWrapper() { ResourceSet = new ODataResourceSet(), Resources = new List <ODataResourceWrapper>() { WritePayloadHelper.CreatePrimaryContactODataWrapper() } }; complexCollection.ResourceSet.SetSerializationInfo(new ODataResourceSerializationInfo() { ExpectedTypeName = NameSpace + "ContactDETAIL" }); ODataWriterHelper.WriteResourceSet(odataWriter, complexCollection); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // [{"@odata.type":"#Microsoft.Test.OData.Services.AstoriaDefaultService.ContactDetails","*****@*****.**":"#Collection(String)"... Assert.IsTrue(result.Contains("\"value\":[{\"@odata.type\":\"#Microsoft.Test.OData.Services.AstoriaDefaultService.ContactDetails\",\"EmailBag")); // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Collection(" + NameSpace + "ContactDETAIL)")); } else { Assert.IsFalse(result.Contains("\"@odata.type\":\"#Microsoft.Test.OData.Services.AstoriaDefaultService.ContactDetails\"")); } } // The following two cases of wrong reference link info is no longer active. The ODataEntityReferenceLinkSerializationInfo is ignored when writer writes the payload. // Consider removing them. // wrong reference link info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var link = new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") }; messageWriter.WriteEntityReferenceLink(link); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains(this.ServiceUri + "Order(-10)")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.context Assert.IsTrue(result.Contains("$metadata#$ref")); } } // wrong reference links info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var links = new ODataEntityReferenceLinks() { Links = new[] { new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") } }, }; messageWriter.WriteEntityReferenceLinks(links); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains(this.ServiceUri + "Order(-10)")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Collection($ref)")); } } } }
/// <summary> /// Writes the result of a $links query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links) { ODataAtomEntityReferenceLinkSerializer atomEntityReferenceLinkSerializer = new ODataAtomEntityReferenceLinkSerializer(this); atomEntityReferenceLinkSerializer.WriteEntityReferenceLinks(links); }
public void WriteWithoutSerializationInfo() { foreach (var mimeType in this.testMimeTypes) { var settings = new ODataMessageWriterSettings(); settings.ODataUri = new ODataUri() { ServiceRoot = this.ServiceUri }; // write entry without serialization info var responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceWriter(); var entry = this.CreatePersonEntryWithoutSerializationInfo(); var expectedError = mimeType.Contains(MimeTypes.ODataParameterNoMetadata) ? null : "ODataResourceTypeContext_MetadataOrSerializationInfoMissing"; AssertThrows <ODataException>(() => odataWriter.WriteStart(entry), expectedError); } // write feed without serialization info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceSetWriter(); var feed = this.CreatePersonFeed(); var entry = this.CreatePersonEntryWithoutSerializationInfo(); entry.SetSerializationInfo(new ODataResourceSerializationInfo() { NavigationSourceName = "Person", NavigationSourceEntityTypeName = NameSpace + "Person" }); var expectedError = mimeType.Contains(MimeTypes.ODataParameterNoMetadata) ? null : "ODataResourceTypeContext_MetadataOrSerializationInfoMissing"; AssertThrows <ODataException>(() => odataWriter.WriteStart(feed), expectedError); } // write collection without serialization info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataCollectionWriter(); var collectionStart = new ODataCollectionStart() { Name = "BackupContactInfo" }; var expectedError = mimeType.Contains(MimeTypes.ODataParameterNoMetadata) ? null : "ODataContextUriBuilder_TypeNameMissingForTopLevelCollection"; AssertThrows <ODataException>(() => odataWriter.WriteStart(collectionStart), expectedError); } // write a reference link without serialization info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var link = new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") }; messageWriter.WriteEntityReferenceLink(link); // No exception is expected. Simply verify the writing succeeded. if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { Stream stream = responseMessageWithoutModel.GetStream(); Assert.IsTrue(WritePayloadHelper.ReadStreamContent(stream).Contains("$metadata#$ref")); } } // write reference links without serialization info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var links = new ODataEntityReferenceLinks() { Links = new[] { new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") } }, }; messageWriter.WriteEntityReferenceLinks(links); // No exception is expected. Simply verify the writing succeeded. if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { Stream stream = responseMessageWithoutModel.GetStream(); Assert.IsTrue(WritePayloadHelper.ReadStreamContent(stream).Contains("$metadata#Collection($ref)")); } } // write request message containing an entry var requestMessageWithoutModel = new StreamRequestMessage(new MemoryStream(), new Uri(this.ServiceUri + "Person"), "POST"); requestMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(requestMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataResourceWriter(); var entry = this.CreatePersonEntryWithoutSerializationInfo(); odataWriter.WriteStart(entry); odataWriter.WriteEnd(); Stream stream = requestMessageWithoutModel.GetStream(); Assert.IsTrue(WritePayloadHelper.ReadStreamContent(stream).Contains("Person(-5)\",\"PersonId\":-5,\"Name\":\"xhsdckkeqzvlnprheujeycqrglfehtdocildrequohlffazfgtvmddyqsaxrojqxrsckohrakdxlrghgmzqnyruzu\"")); } } }
/// <summary> /// Reads the properties of an entity reference link. /// </summary> /// <param name="entityReferenceLinks">The <see cref="ODataEntityReferenceLinks"/> instance to set the read property values on.</param> /// <param name="propertiesFoundBitField">The bit field with all the properties already read.</param> /// <returns>true if the method found the 'results' property; otherwise false.</returns> private bool ReadEntityReferenceLinkProperties( ODataEntityReferenceLinks entityReferenceLinks, ref ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask propertiesFoundBitField) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.JsonReader.AssertNotBuffering(); while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); switch (propertyName) { case JsonConstants.ODataResultsName: ODataJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound( ref propertiesFoundBitField, ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.Results, JsonConstants.ODataResultsName); this.JsonReader.AssertNotBuffering(); return true; case JsonConstants.ODataCountName: ODataJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound( ref propertiesFoundBitField, ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.Count, JsonConstants.ODataCountName); object countValue = this.JsonReader.ReadPrimitiveValue(); long? count = (long?)ODataJsonReaderUtils.ConvertValue(countValue, EdmCoreModel.Instance.GetInt64(true), this.MessageReaderSettings, this.Version, /*validateNullValue*/ true); ODataJsonReaderUtils.ValidateCountPropertyInEntityReferenceLinks(count); entityReferenceLinks.Count = count; break; case JsonConstants.ODataNextLinkName: ODataJsonReaderUtils.VerifyEntityReferenceLinksWrapperPropertyNotFound( ref propertiesFoundBitField, ODataJsonReaderUtils.EntityReferenceLinksWrapperPropertyBitMask.NextPageLink, JsonConstants.ODataNextLinkName); string nextLinkString = this.JsonReader.ReadStringValue(JsonConstants.ODataNextLinkName); ODataJsonReaderUtils.ValidateEntityReferenceLinksStringProperty(nextLinkString, JsonConstants.ODataNextLinkName); entityReferenceLinks.NextPageLink = this.ProcessUriFromPayload(nextLinkString); break; default: // Skip all unrecognized properties this.JsonReader.SkipValue(); break; } } this.JsonReader.AssertNotBuffering(); return false; }
public void EntityReferenceLinksTest() { string resultUri1String = "http://odata.org/linkresult1"; string resultUri2String = "linkresult2"; string resultUri3String = "http://odata.org/linkresult3"; ODataEntityReferenceLink entityReferenceLink1 = new ODataEntityReferenceLink { Url = new Uri(resultUri1String) }; ODataEntityReferenceLink entityReferenceLink2 = new ODataEntityReferenceLink { Url = new Uri(resultUri2String, UriKind.Relative) }; ODataEntityReferenceLink entityReferenceLink3 = new ODataEntityReferenceLink { Url = new Uri(resultUri3String) }; entityReferenceLink3.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestModel.unknown", new ODataPrimitiveValue(123))); entityReferenceLink3.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.name", new ODataPrimitiveValue(456))); Uri nextPageLink = new Uri("http://odata.org/nextpage"); Uri relativeNextPageLink = new Uri("relative-nextpage", UriKind.Relative); long?[] inputCounts = new long?[] { null, 1, 3, -1, -3, 0, long.MaxValue, long.MinValue }; Uri[] inputNextLinks = new Uri[] { nextPageLink, relativeNextPageLink, null }; ODataInstanceAnnotation[][] inputAnnotations = new ODataInstanceAnnotation[][] { new ODataInstanceAnnotation[0], new ODataInstanceAnnotation[] { new ODataInstanceAnnotation("TestModel.annotation", new ODataPrimitiveValue(321)), new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(654)) } }; ODataEntityReferenceLink[][] inputReferenceLinks = new ODataEntityReferenceLink[][] { new ODataEntityReferenceLink[] { entityReferenceLink1, entityReferenceLink2, entityReferenceLink3 }, new ODataEntityReferenceLink[] { entityReferenceLink1, entityReferenceLink3 }, new ODataEntityReferenceLink[] { entityReferenceLink1 }, new ODataEntityReferenceLink[0], null }; var testCases = inputCounts.SelectMany( inputCount => inputNextLinks.SelectMany( inputNextLink => inputReferenceLinks.Select( (inputReferenceLink, index) => new ODataEntityReferenceLinks { Count = inputCount, Links = inputReferenceLink, NextPageLink = inputNextLink, InstanceAnnotations = inputAnnotations[index == 1 ? 1 : 0] }))); var testDescriptors = testCases.Select( testCase => new PayloadWriterTestDescriptor <ODataEntityReferenceLinks>(this.Settings, testCase, this.CreateExpectedCallback(testCase, /*forceNextLinkAndCountAtEnd*/ false))); // TODO: also cover the cases in protocol v1 (errors for inline count and next page link; different format for JSON) this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent, (testDescriptor, testConfiguration) => { ODataEntityReferenceLinks entityReferenceLinks = testDescriptor.PayloadItems.Single(); testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); if (!testConfiguration.IsRequest) { testConfiguration.MessageWriterSettings.ShouldIncludeAnnotation = ODataUtils.CreateAnnotationFilter("*"); } // When writing JSON lite, always provide a model and a non-null nav prop. // The error cases when a model isn't provided or the nav prop is null are tested in JsonLightEntityReferenceLinkWriterTests if (testConfiguration.Format == ODataFormat.Json) { testDescriptor.Model = CreateModelWithNavProps(); var edmModel = testDescriptor.GetMetadataProvider(); } TestWriterUtils.WriteAndVerifyTopLevelContent( testDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLinks(entityReferenceLinks), this.Assert, baselineLogger: this.Logger); }); }
private static void WriteAndValidate(ODataEntityReferenceLinks referencelinks, string expectedPayload, bool writingResponse = true, bool synchronous = true) { string payload = WriteToString(referencelinks, writingResponse, synchronous); Console.WriteLine(payload); Console.WriteLine(expectedPayload); payload.Should().Be(expectedPayload); }
public void EntityReferenceLinksPropertyAccessOrderTest() { //// NOTE: this tests is important as Astoria relies on this behavior. Astoria only provides a next link after all the entity reference //// links have been written so we must not access the next link before that point. ODataEntityReferenceLink entityReferenceLink1 = new ODataEntityReferenceLink { Url = new Uri("http://odata.org/linkresult1") }; ODataEntityReferenceLink entityReferenceLink2 = new ODataEntityReferenceLink { Url = new Uri("http://odata.org/linkresult2") }; ODataEntityReferenceLink entityReferenceLink3 = new ODataEntityReferenceLink { Url = new Uri("http://odata.org/linkresult3") }; Uri nextPageLink = new Uri("http://odata.org/nextpage"); Uri incorrectNextPageLink = new Uri("http://odata.org/incorrectnextpage"); long correctCountValue = 3; // the expected result instance ODataEntityReferenceLinks expectedResult = new ODataEntityReferenceLinks { Count = 3, Links = new ODataEntityReferenceLink[] { entityReferenceLink1, entityReferenceLink2, entityReferenceLink3 }, NextPageLink = nextPageLink }; PayloadWriterTestDescriptor.WriterTestExpectedResultCallback expectedResultCallback = this.CreateExpectedCallback(expectedResult, /*forceNextLinkAndCountAtEnd*/ true); this.CombinatorialEngineProvider.RunCombinations( this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent.Where(tc => !tc.IsRequest), (testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); // The instance with the proper inline count set but an incorrect next link; as we enumerate the links themselves // we will invalidate the inline count and set the correct next link to guarantee the correct order of property accesses // NOTE: we need to create this new for each iteration since the checking enumerable can (intentionally) only be enumerated once. ODataEntityReferenceLinks testReferenceLink = new ODataEntityReferenceLinks { Count = correctCountValue, // In JSON lite, we will write the next link first if one is available. Otherwise, we'll write it at the end. NextPageLink = testConfiguration.Format == ODataFormat.Json ? null : incorrectNextPageLink }; testReferenceLink.Links = new CheckingEntityReferenceLinkEnumerable( testReferenceLink, correctCountValue, nextPageLink /* correct next link */, entityReferenceLink1, entityReferenceLink2, entityReferenceLink3); PayloadWriterTestDescriptor <ODataEntityReferenceLinks> testDescriptor = new PayloadWriterTestDescriptor <ODataEntityReferenceLinks>(this.Settings, testReferenceLink, expectedResultCallback); IEdmNavigationProperty navProp = null; IEdmEntitySet entitySet = null; // When writing JSON lite, always provide a model and a non-null nav prop. // The error cases when a model isn't provided or the nav prop is null are tested in JsonLightEntityReferenceLinkWriterTests if (testConfiguration.Format == ODataFormat.Json) { testDescriptor.Model = CreateModelWithNavProps(); var edmModel = testDescriptor.GetMetadataProvider(); navProp = GetCollectionNavProp(edmModel); entitySet = GetCollectionEntitySet(edmModel); } ODataEntityReferenceLinks entityReferenceLinks = testDescriptor.PayloadItems.Single(); TestWriterUtils.WriteAndVerifyTopLevelContent( testDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLinks(entityReferenceLinks), this.Assert, baselineLogger: this.Logger); }); }
public void InstanceAnnotationsPropertyShouldNotBeNullAtCreation() { ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks(); referencelinks.InstanceAnnotations.Should().NotBeNull(); referencelinks.InstanceAnnotations.Count.Should().Be(0); }
/// <summary> /// Creates the expected result callback for the provided <paramref name="entityReferenceLinks"/>. /// </summary> /// <param name="entityReferenceLinks">The entity reference links to create the expected result for.</param> /// <param name="forceNextLinkAndCountAtEnd">Whether the next link and count should be expected at the end of the payload for JSON lite.</param> /// <returns>The expected result callback for the <paramref name="entityReferenceLinks"/>.</returns> private WriterTestDescriptor.WriterTestExpectedResultCallback CreateExpectedCallback(ODataEntityReferenceLinks entityReferenceLinks, bool forceNextLinkAndCountAtEnd = false) { long? count = entityReferenceLinks.Count; string nextPageLinkString = entityReferenceLinks.NextPageLink == null ? null : entityReferenceLinks.NextPageLink.OriginalString; return((testConfiguration) => { ExpectedException expectedException = null; if (testConfiguration.IsRequest) { // Top-level EntityReferenceLinks payload write requests are not allowed. expectedException = ODataExpectedExceptions.ODataException("ODataMessageWriter_EntityReferenceLinksInRequestNotAllowed"); } if (expectedException == null) { ODataEntityReferenceLink relativeLink = entityReferenceLinks.Links == null ? null : entityReferenceLinks.Links.FirstOrDefault(l => !l.Url.IsAbsoluteUri); bool nextPageLinkRelative = entityReferenceLinks.NextPageLink == null ? false : !entityReferenceLinks.NextPageLink.IsAbsoluteUri; if ((relativeLink != null || nextPageLinkRelative) && testConfiguration.MessageWriterSettings.BaseUri == null) { // We allow relative Uri strings in JSON Light. if (testConfiguration.Format != ODataFormat.Json) { string relativeUriString = relativeLink == null ? entityReferenceLinks.NextPageLink.OriginalString : relativeLink.Url.OriginalString; expectedException = ODataExpectedExceptions.ODataException("ODataWriter_RelativeUriUsedWithoutBaseUriSpecified", relativeUriString); } } } if (expectedException != null) { return new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = expectedException }; } string[] resultUriStrings = entityReferenceLinks.Links == null ? null : entityReferenceLinks.Links.Select(l => GetResultUri(l.Url, testConfiguration)).ToArray(); List <string> atomStrings = new List <string>(); List <string> jsonLightStrings = new List <string>(); string nextLinkString = null; jsonLightStrings.Add("{"); var jsonLightFirstLine = "$(Indent)\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + "\":\"http://odata.org/test/$metadata#Collection($ref)\","; if ((resultUriStrings == null || resultUriStrings.Length == 0) && !count.HasValue && nextPageLinkString == null && testConfiguration.Format != ODataFormat.Json) { atomStrings.Add(@"<links xmlns=""http://docs.oasis-open.org/odata/ns/data"" />"); } else { atomStrings.Add(@"<links xmlns=""http://docs.oasis-open.org/odata/ns/data"">"); if (count.HasValue) { atomStrings.Add(@"<m:count xmlns:m=""" + TestAtomConstants.ODataMetadataNamespace + @""">" + count.Value + @"</m:count>"); if (!forceNextLinkAndCountAtEnd) { jsonLightFirstLine += "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataCountAnnotationName + "\":\"" + count.Value + "\","; } } if (nextPageLinkString != null && !forceNextLinkAndCountAtEnd) { // In JSON lite, the next link comes at the beginning of the payload if available, but in JSON verbose and ATOM it comes at the end. jsonLightFirstLine += "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataNextLinkAnnotationName + "\":\"" + nextPageLinkString + "\","; } jsonLightFirstLine += "\"value\":["; jsonLightStrings.Add(jsonLightFirstLine); int length = resultUriStrings == null ? 0 : resultUriStrings.Length; if (length == 0) { jsonLightStrings.Add("$(Indent)$(Indent)"); } else { for (int i = 0; i < length; ++i) { atomStrings.Add(@"<uri>" + resultUriStrings[i] + @"</uri>"); if (i == 0) { jsonLightStrings.Add("$(Indent)$(Indent){"); } else { jsonLightStrings.Add("$(Indent)$(Indent)},{"); } jsonLightStrings.Add("$(Indent)$(Indent)$(Indent)" + "\"url\":\"" + resultUriStrings[i] + "\""); if (i == resultUriStrings.Length - 1) { jsonLightStrings.Add("$(Indent)$(Indent)}"); } } } var jsonLightLastLine = "$(Indent)]"; if (count.HasValue && forceNextLinkAndCountAtEnd) { jsonLightLastLine += ",\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataCountAnnotationName + "\":" + count.Value; } if (nextPageLinkString != null) { atomStrings.Add(@"<next>" + nextPageLinkString + @"</next>"); nextLinkString = "\"__next\":\"" + nextPageLinkString + "\""; if (forceNextLinkAndCountAtEnd) { jsonLightLastLine += ",\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataNextLinkAnnotationName + "\":\"" + nextPageLinkString + "\""; } } jsonLightStrings.Add(jsonLightLastLine); jsonLightStrings.Add("}"); atomStrings.Add(@"</links>"); } if (testConfiguration.Format == ODataFormat.Json) { return new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = string.Join("$(NL)", jsonLightStrings), FragmentExtractor = (result) => result }; } else { throw new TestInfrastructureException("Expected ATOM or JSON Lite."); } }); }
public void ShouldWriteForEntityReferenceLinksWithSingleLink() { ODataEntityReferenceLink link = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link } }; string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true}]}"; WriteAndValidate(referencelinks, expectedPayload, writingResponse: false); WriteAndValidate(referencelinks, expectedPayload, writingResponse: true); }
/// <summary> /// Return the collection of links as ODataEntityReferenceLink instances /// </summary> /// <param name="elements">Elements whose uri need to be written out.</param> /// <param name="linksCollection">LinkCollection instance which represents the collection getting written out.</param> /// <returns>Return the collection of links as ODataEntityReferenceLink instances.</returns> private IEnumerable <ODataEntityReferenceLink> GetLinksCollection(QueryResultInfo elements, ODataEntityReferenceLinks linksCollection) { object lastObject = null; IExpandedResult lastExpandedSkipToken = null; while (elements.HasMoved) { object element = elements.Current; IExpandedResult skipToken = null; if (element != null) { IExpandedResult expanded = element as IExpandedResult; if (expanded != null) { element = GetExpandedElement(expanded); skipToken = this.GetSkipToken(expanded); } } this.IncrementSegmentResultCount(); yield return(new ODataEntityReferenceLink { Url = this.GetEntityEditLink(element) }); elements.MoveNext(); lastObject = element; lastExpandedSkipToken = skipToken; } if (this.NeedNextPageLink(elements)) { linksCollection.NextPageLink = this.GetNextLinkUri(lastObject, lastExpandedSkipToken, this.RequestDescription.ResultUri); yield break; } }
/// <summary> /// Reads the entity reference link instance annotations. /// </summary> /// <param name="links">The <see cref="ODataEntityReferenceLinks"/> to read the annotations for.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the entity reference links scope.</param> /// <param name="forLinksStart">true when parsing the instance annotations before the 'value' property; /// false when parsing the instance annotations after the 'value' property.</param> /// <remarks> /// Pre-Condition: JsonNodeType.Property The first property in the payload (or the first property after the metadata URI in responses) /// JsonNodeType.EndObject The end of the entity reference links object /// Post-Condition: JsonNodeType.EndObject When the end of the entity reference links object is reached /// Any The first node of the value of the 'url' property (if found) /// </remarks> private void ReadEntityReferenceLinksAnnotations(ODataEntityReferenceLinks links, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool forLinksStart) { Debug.Assert(links != null, "links != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); this.JsonReader.AssertNotBuffering(); while (this.JsonReader.NodeType == JsonNodeType.Property) { // OData property annotations are not supported on entity reference links. Func <string, object> propertyAnnotationValueReader = annotationName => { throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_PropertyAnnotationForEntityReferenceLinks); }; bool foundValueProperty = false; this.ProcessProperty( duplicatePropertyNamesChecker, propertyAnnotationValueReader, (propertyParseResult, propertyName) => { switch (propertyParseResult) { case PropertyParsingResult.ODataInstanceAnnotation: if (string.CompareOrdinal(ODataAnnotationNames.ODataNextLink, propertyName) == 0) { this.ReadEntityReferenceLinksNextLinkAnnotationValue(links); } else if (string.CompareOrdinal(ODataAnnotationNames.ODataCount, propertyName) == 0) { this.ReadEntityReferenceCountAnnotationValue(links); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName)); } break; case PropertyParsingResult.CustomInstanceAnnotation: this.JsonReader.SkipValue(); break; case PropertyParsingResult.PropertyWithValue: if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) != 0) { // We did not find a supported link collection property; fail. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidEntityReferenceLinksPropertyFound(propertyName, JsonLightConstants.ODataValuePropertyName)); } // We found the link collection property and are done parsing property annotations; foundValueProperty = true; break; case PropertyParsingResult.PropertyWithoutValue: // If we find a property without a value it means that we did not find the entity reference links property (yet) // but an invalid property annotation throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_InvalidPropertyAnnotationInEntityReferenceLinks(propertyName)); case PropertyParsingResult.EndOfObject: break; case PropertyParsingResult.MetadataReferenceProperty: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName)); default: throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntityReferenceLinkDeserializer_ReadEntityReferenceLinksAnnotations)); } }); if (foundValueProperty) { return; } } if (forLinksStart) { // We did not find the 'value' property. throw new ODataException(ODataErrorStrings.ODataJsonLightEntityReferenceLinkDeserializer_ExpectedEntityReferenceLinksPropertyNotFound(JsonLightConstants.ODataValuePropertyName)); } this.AssertJsonCondition(JsonNodeType.EndObject); }
/// <summary> /// Visits an item in the object model. /// </summary> /// <param name="objectModelItem">The item to visit.</param> public virtual void Visit(object objectModelItem) { ODataResourceSet resourceCollection = objectModelItem as ODataResourceSet; if (resourceCollection != null) { this.VisitFeed(resourceCollection); return; } ODataResource entry = objectModelItem as ODataResource; if (entry != null) { this.VisitEntry(entry); return; } ODataProperty property = objectModelItem as ODataProperty; if (property != null) { this.VisitProperty(property); return; } ODataNestedResourceInfo navigationLink = objectModelItem as ODataNestedResourceInfo; if (navigationLink != null) { this.VisitNavigationLink(navigationLink); return; } ODataResourceValue resourceValue = objectModelItem as ODataResourceValue; if (resourceValue != null) { this.VisitResourceValue(resourceValue); return; } ODataCollectionValue collectionValue = objectModelItem as ODataCollectionValue; if (collectionValue != null) { this.VisitCollectionValue(collectionValue); return; } ODataStreamReferenceValue streamReferenceValue = objectModelItem as ODataStreamReferenceValue; if (streamReferenceValue != null) { this.VisitStreamReferenceValue(streamReferenceValue); return; } ODataCollectionStart collectionStart = objectModelItem as ODataCollectionStart; if (collectionStart != null) { this.VisitCollectionStart(collectionStart); return; } ODataServiceDocument serviceDocument = objectModelItem as ODataServiceDocument; if (serviceDocument != null) { this.VisitServiceDocument(serviceDocument); return; } ODataEntitySetInfo entitySetInfo = objectModelItem as ODataEntitySetInfo; if (entitySetInfo != null) { this.VisitEntitySet(entitySetInfo); return; } ODataError error = objectModelItem as ODataError; if (error != null) { this.VisitError(error); return; } ODataInnerError innerError = objectModelItem as ODataInnerError; if (innerError != null) { this.VisitInnerError(innerError); return; } ODataEntityReferenceLinks entityReferenceLinks = objectModelItem as ODataEntityReferenceLinks; if (entityReferenceLinks != null) { this.VisitEntityReferenceLinks(entityReferenceLinks); return; } ODataEntityReferenceLink entityReferenceLink = objectModelItem as ODataEntityReferenceLink; if (entityReferenceLink != null) { this.VisitEntityReferenceLink(entityReferenceLink); return; } ODataAction action = objectModelItem as ODataAction; if (action != null) { this.VisitODataOperation(action); return; } ODataFunction function = objectModelItem as ODataFunction; if (function != null) { this.VisitODataOperation(function); return; } ODataParameters parameters = objectModelItem as ODataParameters; if (parameters != null) { this.VisitParameters(parameters); return; } ODataBatch batch = objectModelItem as ODataBatch; if (batch != null) { this.VisitBatch(batch); return; } ODataBatchChangeset batchChangeset = objectModelItem as ODataBatchChangeset; if (batchChangeset != null) { this.VisitBatchChangeset(batchChangeset); return; } ODataBatchRequestOperation batchRequestOperation = objectModelItem as ODataBatchRequestOperation; if (batchRequestOperation != null) { this.VisitBatchRequestOperation(batchRequestOperation); return; } ODataBatchResponseOperation batchResponseOperation = objectModelItem as ODataBatchResponseOperation; if (batchResponseOperation != null) { this.VisitBatchResponseOperation(batchResponseOperation); return; } if (objectModelItem == null || objectModelItem.GetType().IsValueType || objectModelItem is string || objectModelItem is byte[] || objectModelItem is ISpatial) { this.VisitPrimitiveValue(objectModelItem); return; } if (objectModelItem is ODataUntypedValue) { this.VisitPrimitiveValue(ParseJsonToPrimitiveValue((objectModelItem as ODataUntypedValue).RawValue)); return; } this.VisitUnsupportedValue(objectModelItem); }
/// <summary> /// Reads all top-level entity reference links and the (optional) inline count and next link elements. /// </summary> /// <returns>An <see cref="ODataEntityReferenceLinks"/> instance representing the read entity reference links.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The 'feed' element. /// Post-Condition: any - The node after the 'feed' end element (or empty 'feed' element). /// </remarks> private ODataEntityReferenceLinks ReadFeedElement() { Debug.Assert(this.XmlReader != null, "this.XmlReader != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace"); Debug.Assert(this.XmlReader.LocalName == this.ODataFeedElementName, "this.XmlReader.LocalName == AtomConstants.ODataLinksElementName"); ODataEntityReferenceLinks links = new ODataEntityReferenceLinks(); List <ODataEntityReferenceLink> linkList = new List <ODataEntityReferenceLink>(); DuplicateEntityReferenceLinksElementBitMask elementsReadBitmask = DuplicateEntityReferenceLinksElementBitMask.None; if (!this.XmlReader.IsEmptyElement) { // Move to the first child node of the element. this.XmlReader.Read(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.EndElement: // end of the <feed> element continue; case XmlNodeType.Element: // <m:count> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace) && this.XmlReader.LocalNameEquals(this.ODataCountElementName)) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.Count, this.XmlReader.ODataMetadataNamespace, AtomConstants.ODataCountElementName); // Note that we allow negative values to be read. long countValue = (long)AtomValueUtils.ReadPrimitiveValue(this.XmlReader, EdmCoreModel.Instance.GetInt64(false)); links.Count = countValue; // Read over the end element of the <m:count> element this.XmlReader.Read(); continue; } // <m:ref> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace) && this.XmlReader.LocalNameEquals(this.ODataRefElementName)) { ODataEntityReferenceLink link = this.ReadEntityReferenceId(); linkList.Add(link); continue; } // <d:next> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace) && this.XmlReader.LocalNameEquals(this.ODataNextElementName)) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.NextLink, this.XmlReader.ODataNamespace, AtomConstants.ODataNextLinkElementName); // NOTE: get the base URI here before we read the content as string; reading the content as string will move the // reader to the end element and thus we lose the xml:base definition on the element. Uri xmlBaseUri = this.XmlReader.XmlBaseUri; string uriString = this.XmlReader.ReadElementValue(); links.NextPageLink = this.ProcessUriFromPayload(uriString, xmlBaseUri); continue; } break; default: break; } this.XmlReader.Skip(); }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } // Read over the end element, or empty start element. this.XmlReader.Read(); links.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(linkList); return(links); }
public void EntityReferenceLinkValidationTest() { var testCases = new[] { new { InvalidateEntityReferenceLink = new Action <ODataEntityReferenceLink>(entityReferenceLink => entityReferenceLink.Url = null), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_EntityReferenceLinkUrlMustNotBeNull"), }, }; var testDescriptors = testCases.SelectMany(testCase => { ODataEntityReferenceLink entityReferenceLink = ObjectModelUtils.CreateDefaultEntityReferenceLink(); testCase.InvalidateEntityReferenceLink(entityReferenceLink); ODataEntityReferenceLinks entityReferenceLinks = ObjectModelUtils.CreateDefaultEntityReferenceLinks(); testCase.InvalidateEntityReferenceLink(entityReferenceLinks.Links.First()); return(new PayloadWriterTestDescriptor[] { // Top level entity reference link new PayloadWriterTestDescriptor <ODataEntityReferenceLink>( this.Settings, entityReferenceLink, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException }), // Entity reference link in entity reference links new PayloadWriterTestDescriptor <ODataEntityReferenceLinks>( this.Settings, entityReferenceLinks, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { // Top-level EntityReferenceLinks payload write requests are not allowed. ExpectedException2 = testConfiguration.IsRequest ? ODataExpectedExceptions.ODataException("ODataMessageWriter_EntityReferenceLinksInRequestNotAllowed") : testCase.ExpectedException }), new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultSingletonLink(), entityReferenceLink, null, null }, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testConfiguration.IsRequest ? testCase.ExpectedException : ODataExpectedExceptions.ODataException("ODataWriterCore_EntityReferenceLinkInResponse") }), }); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); PayloadWriterTestDescriptor <ODataEntityReferenceLink> entityReferenceLinkTestDescriptor = testDescriptor as PayloadWriterTestDescriptor <ODataEntityReferenceLink>; if (entityReferenceLinkTestDescriptor != null) { TestWriterUtils.WriteAndVerifyTopLevelContent( entityReferenceLinkTestDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLink(entityReferenceLinkTestDescriptor.PayloadItems.Single()), this.Assert, baselineLogger: this.Logger); return; } PayloadWriterTestDescriptor <ODataEntityReferenceLinks> entityReferenceLinksTestDescriptor = testDescriptor as PayloadWriterTestDescriptor <ODataEntityReferenceLinks>; if (entityReferenceLinksTestDescriptor != null) { TestWriterUtils.WriteAndVerifyTopLevelContent( entityReferenceLinksTestDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLinks(entityReferenceLinksTestDescriptor.PayloadItems.Single()), this.Assert, baselineLogger: this.Logger); return; } TestWriterUtils.WriteAndVerifyODataPayload((PayloadWriterTestDescriptor <ODataItem>)testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
/// <summary> /// Writes the result of a $ref query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links) { ODataAtomEntityReferenceLinkSerializer atomEntityReferenceLinkSerializer = new ODataAtomEntityReferenceLinkSerializer(this); atomEntityReferenceLinkSerializer.WriteEntityReferenceLinks(links); }
public void ShouldReadForEntityReferenceLinksWithSingleLink() { ODataEntityReferenceLink link = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link } }; var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true}]}"); ODataEntityReferenceLinks links = deserializer.ReadEntityReferenceLinks(); SameEntityReferenceLinks(referencelinks, links); }
/// <summary> /// Visits an entity reference link collection. /// </summary> /// <param name="entityReferenceLinks">The entity reference link collection to visit.</param> protected abstract T VisitEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks);
public void ShouldReadForEntityReferenceLinksWithReferenceLinksAnnotations() { ODataEntityReferenceLink link1 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link1.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLink link2 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(2)") }; link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.unknown", new ODataPrimitiveValue(123))); link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(456))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link1, link2 } }; referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.name", new ODataPrimitiveValue(321))); referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.name", new ODataPrimitiveValue(654))); string payload = "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"@TestNamespace.name\":321,\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true},{\"@odata.id\":\"http://host/Customers(2)\",\"@TestNamespace.unknown\":123,\"@custom.annotation\":456}],\"@custom.name\":654}"; var deserializer = this.CreateJsonLightEntryAndFeedDeserializer(payload); ODataEntityReferenceLinks links = deserializer.ReadEntityReferenceLinks(); SameEntityReferenceLinks(referencelinks, links); }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { if (this.TryDispatch(requestMessage, responseMessage)) { return; } this.QueryContext.InitializeServerDrivenPaging(this.PreferenceContext); this.QueryContext.InitializeTrackingChanges(this.PreferenceContext); object queryResults = this.QueryContext.ResolveQuery(this.DataSource); if (queryResults == null) { // For individual property or $value if (this.QueryContext.Target.Property != null) { // Protocol 9.1.4 Response Code 204 No Content // A request returns 204 No Content if the requested resource has the null value, // or if the service applies a return=minimal preference. In this case, the response body MUST be empty. ResponseWriter.WriteEmptyResponse(responseMessage); return; } else { throw Utility.BuildException(HttpStatusCode.NotFound); } } // Handle the prefer of "odata.include-annotations", including it in response header if (!string.IsNullOrEmpty(this.PreferenceContext.IncludeAnnotations)) { responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_IncludeAnnotations, this.PreferenceContext.IncludeAnnotations)); } if (this.PreferenceContext.MaxPageSize.HasValue) { responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_MaxPageSize, this.QueryContext.appliedPageSize.Value)); } if (this.PreferenceContext.TrackingChanges) { responseMessage.AddPreferenceApplied(ServiceConstants.Preference_TrackChanging); } responseMessage.SetStatusCode(HttpStatusCode.OK); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { IEdmNavigationSource navigationSource = this.QueryContext.Target.NavigationSource; IEnumerable iEnumerableResults = queryResults as IEnumerable; if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { // Query a $ref collection IList <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>(); foreach (var iEnumerableResult in iEnumerableResults) { var link = new ODataEntityReferenceLink { Url = Utility.BuildLocationUri(this.QueryContext, iEnumerableResult), }; links.Add(link); } ODataEntityReferenceLinks linksCollection = new ODataEntityReferenceLinks() { Links = links, NextPageLink = this.QueryContext.NextLink }; messageWriter.WriteEntityReferenceLinks(linksCollection); } else if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity) { // Query a $ref var link = new ODataEntityReferenceLink { Url = Utility.BuildLocationUri(this.QueryContext, queryResults), }; messageWriter.WriteEntityReferenceLink(link); } else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { // Query a feed IEdmEntitySetBase entitySet = navigationSource as IEdmEntitySetBase; IEdmEntityType entityType = this.QueryContext.Target.ElementType as IEdmEntityType; if (entitySet == null || entityType == null) { throw new InvalidOperationException("Invalid target when query feed."); } ODataWriter resultWriter = messageWriter.CreateODataFeedWriter(entitySet, entityType); ResponseWriter.WriteFeed(resultWriter, iEnumerableResults, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.QueryContext.TotalCount, this.QueryContext.DeltaLink, this.QueryContext.NextLink, this.RequestHeaders); resultWriter.Flush(); } else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity) { var currentETag = Utility.GetETagValue(queryResults); // if the current entity has ETag field if (currentETag != null) { string requestETag; if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag) && (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == currentETag)) { ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.NotModified); return; } responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag); } // Query a single entity IEdmEntityType entityType = this.QueryContext.Target.Type as IEdmEntityType; ODataWriter resultWriter = messageWriter.CreateODataEntryWriter(navigationSource, entityType); ResponseWriter.WriteEntry(resultWriter, queryResults, navigationSource, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.RequestHeaders); resultWriter.Flush(); } else if (this.QueryContext.Target.Property != null && !this.QueryContext.Target.IsRawValue) { // Query a individual property ODataProperty property = ODataObjectModelConverter.CreateODataProperty(queryResults, this.QueryContext.Target.Property.Name); messageWriter.WriteProperty(property); } else if (this.QueryContext.Target.IsRawValue) { // Query a $value or $count var propertyValue = ODataObjectModelConverter.CreateODataValue(queryResults); messageWriter.WriteValue(propertyValue); } else { throw Utility.BuildException(HttpStatusCode.NotImplemented); } } }
/// <summary> /// Reads all top-level entity reference links and the (optional) inline count and next link elements. /// </summary> /// <returns>An <see cref="ODataEntityReferenceLinks"/> instance representing the read entity reference links.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The 'feed' element. /// Post-Condition: any - The node after the 'feed' end element (or empty 'feed' element). /// </remarks> private ODataEntityReferenceLinks ReadFeedElement() { Debug.Assert(this.XmlReader != null, "this.XmlReader != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace"); Debug.Assert(this.XmlReader.LocalName == this.ODataFeedElementName, "this.XmlReader.LocalName == AtomConstants.ODataLinksElementName"); ODataEntityReferenceLinks links = new ODataEntityReferenceLinks(); List<ODataEntityReferenceLink> linkList = new List<ODataEntityReferenceLink>(); DuplicateEntityReferenceLinksElementBitMask elementsReadBitmask = DuplicateEntityReferenceLinksElementBitMask.None; if (!this.XmlReader.IsEmptyElement) { // Move to the first child node of the element. this.XmlReader.Read(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.EndElement: // end of the <feed> element continue; case XmlNodeType.Element: // <m:count> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace) && this.XmlReader.LocalNameEquals(this.ODataCountElementName)) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.Count, this.XmlReader.ODataMetadataNamespace, AtomConstants.ODataCountElementName); // Note that we allow negative values to be read. long countValue = (long)AtomValueUtils.ReadPrimitiveValue(this.XmlReader, EdmCoreModel.Instance.GetInt64(false)); links.Count = countValue; // Read over the end element of the <m:count> element this.XmlReader.Read(); continue; } // <m:ref> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace) && this.XmlReader.LocalNameEquals(this.ODataRefElementName)) { ODataEntityReferenceLink link = this.ReadEntityReferenceId(); linkList.Add(link); continue; } // <d:next> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace) && this.XmlReader.LocalNameEquals(this.ODataNextElementName)) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.NextLink, this.XmlReader.ODataNamespace, AtomConstants.ODataNextLinkElementName); // NOTE: get the base URI here before we read the content as string; reading the content as string will move the // reader to the end element and thus we lose the xml:base definition on the element. Uri xmlBaseUri = this.XmlReader.XmlBaseUri; string uriString = this.XmlReader.ReadElementValue(); links.NextPageLink = this.ProcessUriFromPayload(uriString, xmlBaseUri); continue; } break; default: break; } this.XmlReader.Skip(); } while (this.XmlReader.NodeType != XmlNodeType.EndElement); } // Read over the end element, or empty start element. this.XmlReader.Read(); links.Links = new ReadOnlyEnumerable<ODataEntityReferenceLink>(linkList); return links; }
/// <summary> /// Writes the result of a $ref query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links) { ODataJsonLightEntityReferenceLinkSerializer jsonLightEntityReferenceLinkSerializer = new ODataJsonLightEntityReferenceLinkSerializer(this); jsonLightEntityReferenceLinkSerializer.WriteEntityReferenceLinks(links); }
/// <summary> /// Asynchronously writes the result of a $ref query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> /// <returns>A task representing the asynchronous writing of the entity reference links.</returns> /// <remarks>It is the responsibility of this method to flush the output before the task finishes.</remarks> internal override Task WriteEntityReferenceLinksAsync(ODataEntityReferenceLinks links) { this.AssertAsynchronous(); return TaskUtils.GetTaskForSynchronousOperationReturningTask( () => { this.WriteEntityReferenceLinksImplementation(links); return this.FlushAsync(); }); }
/// <summary> /// Writes the result of a $links query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> /// <remarks>It is the responsibility of this method to flush the output before the method returns.</remarks> internal override void WriteEntityReferenceLinks(ODataEntityReferenceLinks links) { DebugUtils.CheckNoExternalCallers(); this.AssertSynchronous(); this.WriteEntityReferenceLinksImplementation(links); this.Flush(); }
private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links) { new ODataJsonEntityReferenceLinkSerializer(this).WriteEntityReferenceLinks(links); }
public void WriteForEntityReferenceLinksWithDuplicateAnnotationNameShouldThrow() { ODataEntityReferenceLink link1 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link1.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLink link2 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(2)") }; link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.unknown", new ODataPrimitiveValue(123))); link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(456))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link1, link2 } }; referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.name", new ODataPrimitiveValue(321))); referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.name", new ODataPrimitiveValue(654))); string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"@TestNamespace.name\":321,\"@TestNamespace.name\":654,\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true},{\"@odata.id\":\"http://host/Customers(2)\",\"@TestNamespace.unknown\":123,\"@custom.annotation\":456}]}"; Action writeResult = () => WriteAndValidate(referencelinks, expectedPayload, writingResponse: false); writeResult.ShouldThrow<ODataException>().WithMessage(ODataErrorStrings.JsonLightInstanceAnnotationWriter_DuplicateAnnotationNameInCollection("TestNamespace.name")); writeResult = () => WriteAndValidate(referencelinks, expectedPayload, writingResponse: true); writeResult.ShouldThrow<ODataException>().WithMessage(ODataErrorStrings.JsonLightInstanceAnnotationWriter_DuplicateAnnotationNameInCollection("TestNamespace.name")); }
public void WriteEntryWithWrongSerializationInfo() { foreach (var mimeType in this.testMimeTypes) { var settings = new ODataMessageWriterSettings(); settings.ODataUri = new ODataUri() { ServiceRoot = this.ServiceUri }; // wrong EntitySetName for entry var responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataEntryWriter(); var entry = this.CreatePersonEntryWithoutSerializationInfo(); entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Parsen", NavigationSourceEntityTypeName = NameSpace + "Person" }); odataWriter.WriteStart(entry); odataWriter.WriteEnd(); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains("Person(-5)\",\"PersonId\":-5")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Parsen/$entity")); } } // wrong EntitySetName for feed responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataFeedWriter(); var feed = this.CreatePersonFeed(); feed.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo() { NavigationSourceName = "Parsen", NavigationSourceEntityTypeName = NameSpace + "Person" }); var entry = this.CreatePersonEntryWithoutSerializationInfo(); odataWriter.WriteStart(feed); odataWriter.WriteStart(entry); odataWriter.WriteEnd(); odataWriter.WriteEnd(); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains("Person(-5)\",\"PersonId\":-5")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Parsen\"")); } } // wrong collection type name responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var odataWriter = messageWriter.CreateODataCollectionWriter(); var collctionStart = new ODataCollectionStart() { Name = "BackupContactInfo" }; collctionStart.SetSerializationInfo(new ODataCollectionStartSerializationInfo() { CollectionTypeName = "Collection(" + NameSpace + "ContactDETAIL)" }); odataWriter.WriteStart(collctionStart); odataWriter.WriteItem( WritePayloadHelper.CreatePrimaryContactODataComplexValue()); odataWriter.WriteEnd(); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains("value\":[{\"EmailBag\":[")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Collection(" + NameSpace + "ContactDETAIL)")); } } // The following two cases of wrong reference link info is no longer active. The ODataEntityReferenceLinkSerializationInfo is ignored when writer writes the payload. // Consider removing them. // wrong reference link info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var link = new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") }; messageWriter.WriteEntityReferenceLink(link); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains(this.ServiceUri + "Order(-10)")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.context Assert.IsTrue(result.Contains("$metadata#$ref")); } } // wrong reference links info responseMessageWithoutModel = new StreamResponseMessage(new MemoryStream()); responseMessageWithoutModel.SetHeader("Content-Type", mimeType); using (var messageWriter = new ODataMessageWriter(responseMessageWithoutModel, settings)) { var links = new ODataEntityReferenceLinks() { Links = new[] { new ODataEntityReferenceLink() { Url = new Uri(this.ServiceUri + "Order(-10)") } }, }; messageWriter.WriteEntityReferenceLinks(links); var result = WritePayloadHelper.ReadStreamContent(responseMessageWithoutModel.GetStream()); Assert.IsTrue(result.Contains(this.ServiceUri + "Order(-10)")); if (!mimeType.Contains(MimeTypes.ODataParameterNoMetadata)) { // no metadata does not write odata.metadata Assert.IsTrue(result.Contains("$metadata#Collection($ref)")); } } } }
/// <summary> /// Writes the result of a $ref query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> /// <remarks>It is the responsibility of this method to flush the output before the method returns.</remarks> internal override void WriteEntityReferenceLinks(ODataEntityReferenceLinks links) { this.AssertSynchronous(); this.WriteEntityReferenceLinksImplementation(links); this.Flush(); }
public void ShouldWriteAndReadForEntityReferenceLinksWithReferenceLinksAnnotation() { ODataEntityReferenceLink link1 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link1.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLink link2 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(2)") }; link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.unknown", new ODataPrimitiveValue(123))); link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(456))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link1, link2 } }; referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.name", new ODataPrimitiveValue(321))); referencelinks.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.name", new ODataPrimitiveValue(654))); string midplayoad = WriteToString(referencelinks, writingResponse: false); var deserializer = this.CreateJsonLightEntryAndFeedDeserializer(midplayoad); ODataEntityReferenceLinks links = deserializer.ReadEntityReferenceLinks(); SameEntityReferenceLinks(referencelinks, links); }
/// <summary> /// Writes the result of a $ref query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links) { ODataJsonLightEntityReferenceLinkSerializer jsonLightEntityReferenceLinkSerializer = new ODataJsonLightEntityReferenceLinkSerializer(this); jsonLightEntityReferenceLinkSerializer.WriteEntityReferenceLinks(links); }
private static void SameEntityReferenceLinks(ODataEntityReferenceLinks links1, ODataEntityReferenceLinks links2) { links1.Should().NotBeNull(); links2.Should().NotBeNull(); links1.Links.Should().NotBeNull(); links2.Links.Should().NotBeNull(); links1.Links.Count().Should().Equals(links2.Links.Count()); for (var i = 0; i < links1.Links.Count(); ++i) { SameEntityReferenceLink(links1.Links.ElementAt(i), links2.Links.ElementAt(i)); } SameInstanceAnnotations(links1.InstanceAnnotations, links2.InstanceAnnotations); }
public void WriteTopLevelEntityReferenceLinks() { ODataEntityReferenceLink link1 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(1)") }; link1.InstanceAnnotations.Add(new ODataInstanceAnnotation("Is.New", new ODataPrimitiveValue(true))); ODataEntityReferenceLink link2 = new ODataEntityReferenceLink { Url = new Uri("http://host/Customers(2)") }; link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("TestNamespace.unknown", new ODataPrimitiveValue(123))); link2.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.annotation", new ODataPrimitiveValue(456))); ODataEntityReferenceLinks referencelinks = new ODataEntityReferenceLinks() { Links = new[] { link1, link2 } }; var writerSettings = new ODataMessageWriterSettings { DisableMessageStreamDisposal = true }; writerSettings.SetContentType(ODataFormat.Json); writerSettings.SetServiceDocumentUri(new Uri("http://odata.org/test")); MemoryStream stream = new MemoryStream(); IODataResponseMessage requestMessageToWrite = new InMemoryMessage { StatusCode = 200, Stream = stream }; requestMessageToWrite.PreferenceAppliedHeader().AnnotationFilter = "*"; using (var messageWriter = new ODataMessageWriter(requestMessageToWrite, writerSettings, EdmModel)) { messageWriter.WriteEntityReferenceLinks(referencelinks); } stream.Position = 0; string payload = (new StreamReader(stream)).ReadToEnd(); string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#Collection($ref)\",\"value\":[{\"@odata.id\":\"http://host/Customers(1)\",\"@Is.New\":true},{\"@odata.id\":\"http://host/Customers(2)\",\"@TestNamespace.unknown\":123,\"@custom.annotation\":456}]}"; Assert.Equal(expectedPayload, payload); }
/// <summary> /// Writes the result of a $links query as the message payload. /// </summary> /// <param name="links">The entity reference links to write as message payload.</param> /// <param name="entitySet">The entity set of the navigation property.</param> /// <param name="navigationProperty">The navigation property for which the entity reference links are being written, or null if none is available.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks links, IEdmEntitySet entitySet, IEdmNavigationProperty navigationProperty) { ODataJsonLightEntityReferenceLinkSerializer jsonLightEntityReferenceLinkSerializer = new ODataJsonLightEntityReferenceLinkSerializer(this); jsonLightEntityReferenceLinkSerializer.WriteEntityReferenceLinks(links, entitySet, navigationProperty); }