private void WriteEntry(ODataWriter writer, Lazy <ODataReader> lazyReader, ODataResource entry) { this.WriteStart(writer, entry); var annotation = entry.GetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>(); ODataNestedResourceInfo navLink = null; if (annotation != null) { for (int i = 0; i < annotation.Count; ++i) { bool found = annotation.TryGetNavigationLinkAt(i, out navLink); ExceptionUtilities.Assert(found, "Navigation links should be ordered sequentially for writing"); this.WriteNavigationLink(writer, lazyReader, navLink); } } this.WriteEnd(writer, ODataReaderState.ResourceEnd); this.Read(lazyReader); }
private void WriteAnnotationOnExpandedEntryInExpandedFeed(IEdmNavigationSource navigationSource, string expectedPayload, ODataFormat format) { Action <ODataWriter> action = (odataWriter) => { var entryToWrite = new ODataResource { Properties = new[] { new ODataProperty { Name = "ID", Value = 1 } } }; odataWriter.WriteStart(entryToWrite); ODataNestedResourceInfo navLink = new ODataNestedResourceInfo { Name = "ResourceSetNavigationProperty", IsCollection = true }; odataWriter.WriteStart(navLink); var feedToWrite = new ODataResourceSet { Id = new Uri("urn:feedId") }; odataWriter.WriteStart(feedToWrite); entryToWrite = new ODataResource { Properties = new[] { new ODataProperty { Name = "ID", Value = 1 } } }; entryToWrite.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.StartAnnotation", PrimitiveValue1)); entryToWrite.ETag = "ETag"; odataWriter.WriteStart(entryToWrite); entryToWrite.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.EndAnnotation", PrimitiveValue1)); odataWriter.WriteEnd(); odataWriter.WriteEnd(); odataWriter.WriteEnd(); odataWriter.WriteEnd(); }; this.WriteAnnotationsAndValidatePayload(action, navigationSource, format, expectedPayload, request: false, createFeedWriter: false); this.WriteAnnotationsAndValidatePayload(action, navigationSource, format, expectedPayload, request: true, createFeedWriter: false); }
public void ReadingSingleNavigationProppertyWithAllowedTypeAsNavigationPropertyTypeWithOrWithoutDerivedTypeConstraintWorks() { // Add a <NavigationProperty Name="FriendCustomer" Type="NS.Customer" /> var navigationProperty = this.edmCustomerType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Target = this.edmCustomerType, TargetMultiplicity = EdmMultiplicity.One, Name = "FriendCustomer" }); Action <Stack <ODataItem> > verifyItems = (ms) => { Assert.NotNull(ms); Assert.Equal(4, ms.Count); ODataResource resource = Assert.IsType <ODataResource>(ms.Pop()); // top level resource (id=7) Assert.Equal(7, resource.Properties.Single().Value); ODataNestedResourceInfo nestedLink = Assert.IsType <ODataNestedResourceInfo>(ms.Pop()); // FriendCustomer Navigation Link Assert.Equal(new Uri("http://example.com/Customers(7)/FriendCustomer"), nestedLink.Url); Assert.Equal("FriendCustomer", nestedLink.Name); resource = Assert.IsType <ODataResource>(ms.Pop()); // nested resource (id=8) Assert.Equal(8, resource.Properties.Single().Value); Assert.Equal("NS.VipCustomer", resource.TypeName); ODataNestedResourceInfo nestedResourceInfo = Assert.IsType <ODataNestedResourceInfo>(ms.Pop()); // FriendCustomer Nested resource info Assert.Throws <ODataException>(() => nestedResourceInfo.Url); Assert.Equal("FriendCustomer", nestedResourceInfo.Name); }; string payload = "{\"@odata.context\":\"http://example.com/$metadata#Customers/$entity\",\"Id\":7,\"FriendCustomer\":{\"@odata.type\":\"#NS.VipCustomer\",\"Id\":8}}"; // Navigation property doesn't have the derived type constraint. var items = ReadEntityPayload(payload, this.edmModel, this.edmCustomers, this.edmCustomerType); verifyItems(items); // Navigation property has the derived type constraint. SetDerivedTypeAnnotation(this.edmModel, navigationProperty, "NS.VipCustomer"); items = ReadEntityPayload(payload, this.edmModel, this.edmCustomers, this.edmCustomerType); verifyItems(items); }
/// <summary> /// Adds a navigation link. /// </summary> /// <param name="link">The link.</param> public void AddNestedResourceInfo(ODataNestedResourceInfo link) { if (this.IsTracking) { this.EntityDescriptor.AddNestedResourceInfo(link.Name, link.Url); Uri associationLinkUrl = link.AssociationLinkUrl; if (associationLinkUrl != null) { this.EntityDescriptor.AddAssociationLink(link.Name, associationLinkUrl); } } if (this.navigationLinks == ODataMaterializer.EmptyLinks) { this.navigationLinks = new List <ODataNestedResourceInfo>(); } this.navigationLinks.Add(link); }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> protected virtual void VisitNavigationLink(ODataNestedResourceInfo navigationLink) { object expandedContent; if (navigationLink.TryGetExpandedContent(out expandedContent) && expandedContent != null) { List <ODataItem> items = expandedContent as List <ODataItem>; if (items != null) { foreach (ODataItem item in items) { this.Visit(item); } } else { this.Visit(expandedContent); } } }
/// <summary> /// Creates a nested resource info for a singleton entity reference link. /// </summary> /// <param name="nestedResourceInfo">The nested resource info to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="entityReferenceLink">The entity reference link for the nested resource info to report.</param> /// <param name="isExpanded">true if the nested resource info is expanded.</param> /// <returns>The nested resource info created.</returns> internal static ODataJsonLightReaderNestedResourceInfo CreateSingletonEntityReferenceLinkInfo( ODataNestedResourceInfo nestedResourceInfo, IEdmNavigationProperty navigationProperty, ODataEntityReferenceLink entityReferenceLink, bool isExpanded) { Debug.Assert(nestedResourceInfo != null, "nestedResourceInfo != null"); Debug.Assert(nestedResourceInfo.IsCollection == false, "Singleton entity reference can only be reported for a singleton navigation links."); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataJsonLightReaderNestedResourceInfo readerNestedResourceInfo = new ODataJsonLightReaderNestedResourceInfo(nestedResourceInfo, navigationProperty, isExpanded); if (entityReferenceLink != null) { readerNestedResourceInfo.entityReferenceLinks = new LinkedList <ODataEntityReferenceLink>(); readerNestedResourceInfo.entityReferenceLinks.AddFirst(entityReferenceLink); } return(readerNestedResourceInfo); }
private void WriteComplexProperties(IEnumerable <IEdmStructuralProperty> complexProperties, ResourceContext resourceContext, ODataWriter writer) { Contract.Assert(complexProperties != null); Contract.Assert(resourceContext != null); Contract.Assert(writer != null); foreach (IEdmStructuralProperty complexProperty in complexProperties) { ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo { IsCollection = complexProperty.Type.IsCollection(), Name = complexProperty.Name }; writer.WriteStart(nestedResourceInfo); WriteComplexAndExpandedNavigationProperty(complexProperty, null, resourceContext, writer); writer.WriteEnd(); } }
private void WriteAnnotationAtEndExpandedFeedShouldFail(ODataFormat format) { Action <ODataWriter> action = (odataWriter) => { var entryToWrite = new ODataResource { Properties = new[] { new ODataProperty { Name = "ID", Value = 1 } } }; odataWriter.WriteStart(entryToWrite); ODataNestedResourceInfo navLink = new ODataNestedResourceInfo { Name = "ResourceSetNavigationProperty", Url = new Uri("http://service/navLink", UriKind.RelativeOrAbsolute), IsCollection = true }; odataWriter.WriteStart(navLink); var feedToWrite = new ODataResourceSet { Id = new Uri("urn:feedId") }; odataWriter.WriteStart(feedToWrite); feedToWrite.InstanceAnnotations.Add(new ODataInstanceAnnotation("custom.StartFeedAnnotation", PrimitiveValue1)); odataWriter.WriteEnd(); }; Action testResponse = () => this.WriteAnnotationsAndValidatePayload(action, EntitySet, format, null, request: false, createFeedWriter: false); testResponse.Throws <ODataException>(Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedResourceSet); Action testResponseOfSingleton = () => this.WriteAnnotationsAndValidatePayload(action, Singleton, format, null, request: false, createFeedWriter: false); testResponseOfSingleton.Throws <ODataException>(Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedResourceSet); Action testRequest = () => this.WriteAnnotationsAndValidatePayload(action, EntitySet, format, null, request: true, createFeedWriter: false); testRequest.Throws <ODataException>(Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedResourceSet); Action testRequestOfSingleton = () => this.WriteAnnotationsAndValidatePayload(action, Singleton, format, null, request: true, createFeedWriter: false); testRequestOfSingleton.Throws <ODataException>(Strings.ODataJsonLightWriter_InstanceAnnotationNotSupportedOnExpandedResourceSet); }
private void WriteNavigationNextLink(OeEntryFactory entryFactory, ExpandedNavigationSelectItem item, Object value) { var segment = (NavigationPropertySegment)item.PathToNavigationProperty.LastSegment; var resourceInfo = new ODataNestedResourceInfo() { IsCollection = true, Name = segment.NavigationProperty.Name }; _writer.WriteStart(resourceInfo); var resourceSet = new ODataResourceSet() { NextPageLink = BuildNavigationNextPageLink(_queryContext.EdmModel, entryFactory, item, value) }; _writer.WriteStart(resourceSet); _writer.WriteEnd(); _writer.WriteEnd(); }
public async Task WriteNavigationLinkMetadataAsync_WritesNavigationLinkMetadata() { var nestedResourceInfo = new ODataNestedResourceInfo { Name = "BestSeller", Url = new Uri($"{ServiceUri}/Categories(1)/BestSeller"), IsCollection = false, AssociationLinkUrl = new Uri($"{ServiceUri}/Categories(1)/associationLink") }; var result = await SetupJsonLightResourceSerializerAndRunTestAsync( (jsonLightResourceSerializer) => { return(jsonLightResourceSerializer.WriteNavigationLinkMetadataAsync( nestedResourceInfo, new NullDuplicatePropertyNameChecker())); }); Assert.Equal("{\"[email protected]\":\"http://tempuri.org/Categories(1)/associationLink\"," + "\"[email protected]\":\"http://tempuri.org/Categories(1)/BestSeller\"", result); }
private async Task WriteNavigation(Db.IOeDbEnumerator dbEnumerator) { bool isCollection = dbEnumerator.EntryFactory.EdmNavigationProperty.Type.Definition is EdmCollectionType; var resourceInfo = new ODataNestedResourceInfo() { IsCollection = isCollection, Name = dbEnumerator.EntryFactory.EdmNavigationProperty.Name }; await _writer.WriteStartAsync(resourceInfo).ConfigureAwait(false); if (isCollection) { await WriteNavigationCollection(dbEnumerator).ConfigureAwait(false); } else { await WriteNavigationSingle(dbEnumerator).ConfigureAwait(false); } await _writer.WriteEndAsync().ConfigureAwait(false); }
private void WriteNavigationNextLink(ODataResource parentEntry, ExpandedNavigationSelectItem item) { var segment = (NavigationPropertySegment)item.PathToNavigationProperty.LastSegment; var resourceInfo = new ODataNestedResourceInfo() { IsCollection = true, Name = segment.NavigationProperty.Name }; Writer.WriteStart(resourceInfo); var resourceSet = new ODataResourceSet() { NextPageLink = BuildNavigationNextPageLink(parentEntry, item) }; Writer.WriteStart(resourceSet); Writer.WriteEnd(); Writer.WriteEnd(); }
public void WritingSingleNavigationProppertyWithNotAllowedTypeWorksWithoutDerivedTypeConstraintButFailedWithDerivedTypeConstraint() { // Add a <NavigationProperty Name="FriendCustomer" Type="NS.Customer" /> var navigationProperty = this.edmCustomerType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Target = this.edmCustomerType, TargetMultiplicity = EdmMultiplicity.One, Name = "FriendCustomer" }); ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo { Name = "FriendCustomer", IsCollection = false }; Action <ODataMessageWriter> writeNavigationPropertyAction = (messageWriter) => { ODataWriter writer = messageWriter.CreateODataResourceWriter(this.edmCustomers, this.edmCustomerType); // entityset writer.WriteStart(this.odataCustomerResource); writer.WriteStart(nestedResourceInfo); writer.WriteStart(this.odataNormalResource); // Normal customer writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); }; // Navigation property doesn't have the derived type constraint. string actual = GetWriterOutput(this.edmModel, writeNavigationPropertyAction); Assert.Contains("#Customers/$entity\",\"Id\":7,\"FriendCustomer\":{\"@odata.type\":\"#NS.NormalCustomer\",\"Id\":9", actual); // Negative test case --Navigation property has the derived type constraint. SetDerivedTypeAnnotation(this.edmModel, navigationProperty, "NS.VipCustomer"); Action test = () => GetWriterOutput(this.edmModel, writeNavigationPropertyAction); var exception = Assert.Throws <ODataException>(test); Assert.Equal(Strings.WriterValidationUtils_ValueTypeNotAllowedInDerivedTypeConstraint("NS.NormalCustomer", "property", "FriendCustomer"), exception.Message); }
private Expression Translate(NavigationPropertySegment segment, bool?countOption) { IEdmNavigationProperty navigationEdmProperty = segment.NavigationProperty; var collectionType = navigationEdmProperty.Type.Definition as IEdmCollectionType; var resourceInfo = new ODataNestedResourceInfo() { IsCollection = collectionType != null, Name = navigationEdmProperty.Name }; var entitySet = (IEdmEntitySet)segment.NavigationSource; if (entitySet == null) { IEdmType entityType; if (collectionType == null) { entityType = navigationEdmProperty.Type.Definition; } else { entityType = collectionType.ElementType.Definition; } foreach (IEdmEntitySet element in _model.EntityContainer.Elements) { if (element.EntityType() == entityType) { entitySet = element; break; } } } _selectItemInfo = new SelectItemInfo(entitySet, navigationEdmProperty, resourceInfo, countOption); PropertyInfo navigationClrProperty = _parameter.Type.GetTypeInfo().GetProperty(navigationEdmProperty.Name); return(Expression.MakeMemberAccess(_parameter, navigationClrProperty)); }
private static void WriteNavigationLinks(ODataWriter writer, object element, Uri parentEntryUri, IEdmEntityType parentEntityType, IEdmModel model, ODataVersion targetVersion, IEnumerable <string> expandedNavigationProperties) { foreach (var navigationProperty in parentEntityType.NavigationProperties()) { IEdmTypeReference propertyTypeReference = navigationProperty.Type; bool isCollection = navigationProperty.Type.IsCollection(); var navigationLink = new ODataNestedResourceInfo { Url = new Uri(parentEntryUri, navigationProperty.Name), IsCollection = isCollection, Name = navigationProperty.Name, }; writer.WriteStart(navigationLink); if (expandedNavigationProperties.Contains(navigationProperty.Name)) { var propertyValue = DataContext.GetPropertyValue(element, navigationProperty.Name); if (propertyValue != null) { var propertyEntityType = propertyTypeReference.Definition as IEdmEntityType; IEdmEntitySet targetEntitySet = model.EntityContainer.EntitySets().Single(s => s.EntityType() == propertyEntityType); if (isCollection) { WriteFeed(writer, propertyValue as IEnumerable, targetEntitySet, model, targetVersion, Enumerable.Empty <string>()); } else { WriteEntry(writer, propertyValue, targetEntitySet, model, targetVersion, Enumerable.Empty <string>()); } } } writer.WriteEnd(); } }
public void WritingSingleNavigationProppertyWithAllowedTypeAsNavigationPropertyTypeWithOrWithoutDerivedTypeConstraintWorks() { // Add a <NavigationProperty Name="FriendCustomer" Type="NS.Customer" /> var navigationProperty = this.edmCustomerType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Target = this.edmCustomerType, TargetMultiplicity = EdmMultiplicity.One, Name = "FriendCustomer" }); ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo { Name = "FriendCustomer", IsCollection = false }; Action <ODataMessageWriter> writeNavigationPropertyAction = (messageWriter) => { ODataWriter writer = messageWriter.CreateODataResourceWriter(this.edmMe, this.edmCustomerType); // singleton writer.WriteStart(this.odataCustomerResource); writer.WriteStart(nestedResourceInfo); writer.WriteStart(this.odataVipResource); // VipCustomer writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); }; // Navigation property doesn't have the derived type constraint. string actual = GetWriterOutput(this.edmModel, writeNavigationPropertyAction); Assert.Contains("#Me\",\"Id\":7,\"FriendCustomer\":{\"@odata.type\":\"#NS.VipCustomer\",\"Id\":8", actual); // Navigation property has the derived type constraint. SetDerivedTypeAnnotation(this.edmModel, navigationProperty, "NS.VipCustomer"); string actualWithDerivedTypeConstraint = GetWriterOutput(this.edmModel, writeNavigationPropertyAction); Assert.Equal(actual, actualWithDerivedTypeConstraint); }
private void WriteExpandedNavigationProperties( IDictionary <IEdmNavigationProperty, SelectExpandClause> navigationPropertiesToExpand, ResourceContext resourceContext, ODataWriter writer) { Contract.Assert(navigationPropertiesToExpand != null); Contract.Assert(resourceContext != null); Contract.Assert(writer != null); foreach (KeyValuePair <IEdmNavigationProperty, SelectExpandClause> navPropertyToExpand in navigationPropertiesToExpand) { IEdmNavigationProperty navigationProperty = navPropertyToExpand.Key; ODataNestedResourceInfo navigationLink = CreateNavigationLink(navigationProperty, resourceContext); if (navigationLink != null) { writer.WriteStart(navigationLink); WriteComplexAndExpandedNavigationProperty(navPropertyToExpand.Key, navPropertyToExpand.Value, resourceContext, writer); writer.WriteEnd(); } } }
private async Task WriteDynamicComplexPropertiesAsync(ResourceContext resourceContext, ODataWriter writer) { Contract.Assert(resourceContext != null); Contract.Assert(resourceContext.EdmModel != null); if (resourceContext.DynamicComplexProperties == null) { return; } foreach (var dynamicComplexProperty in resourceContext.DynamicComplexProperties) { // If the dynamic property is "null", it should be treated ahead by creating an ODataProperty with ODataNullValue. // However, it's safety here to skip the null dynamic property. if (String.IsNullOrEmpty(dynamicComplexProperty.Key) || dynamicComplexProperty.Value == null) { continue; } IEdmTypeReference edmTypeReference = resourceContext.SerializerContext.GetEdmType(dynamicComplexProperty.Value, dynamicComplexProperty.Value.GetType()); if (edmTypeReference.IsStructured() || (edmTypeReference.IsCollection() && edmTypeReference.AsCollection().ElementType().IsStructured())) { ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo { IsCollection = edmTypeReference.IsCollection(), Name = dynamicComplexProperty.Key, }; writer.WriteStart(nestedResourceInfo); await WriteDynamicComplexPropertyAsync(dynamicComplexProperty.Value, edmTypeReference, resourceContext, writer); writer.WriteEnd(); } } }
public void WritingMultipleComplexProppertyWithOrWithoutDerivedTypeConstraintWorks() { // Add a <Property Name="Locations" Type="Collection(NS.Address)" /> var locationsProperty = this.edmCustomerType.AddStructuralProperty("Locations", new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(this.edmAddressType, false)))); ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo { Name = "Locations", IsCollection = true }; Action <ODataMessageWriter> writePropertyAction = (messageWriter) => { ODataWriter writer = messageWriter.CreateODataResourceWriter(this.edmCustomers, this.edmCustomerType); // entityset writer.WriteStart(this.odataCustomerResource); writer.WriteStart(nestedResourceInfo); writer.WriteStart(new ODataResourceSet()); writer.WriteStart(this.odataCnAddressResource); // CnAddress writer.WriteEnd(); writer.WriteStart(this.odataUsAddressResource); // UsAddress writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); }; // Structural property doesn't have the derived type constraint. string usAddressActual = GetWriterOutput(this.edmModel, writePropertyAction); Assert.Contains(",\"Id\":7,\"Locations\":[{\"@odata.type\":\"#NS.CnAddress\",\"Street\":\"Sha", usAddressActual); // Negative test case --Structural property has the derived type constraint. SetDerivedTypeAnnotation(this.edmModel, locationsProperty, "NS.CnAddress"); Action test = () => GetWriterOutput(this.edmModel, writePropertyAction); var exception = Assert.Throws <ODataException>(test); Assert.Equal(Strings.WriterValidationUtils_ValueTypeNotAllowedInDerivedTypeConstraint("NS.UsAddress", "property", "Locations"), exception.Message); }
/// <summary> /// Returns all interesting payloads for a navigation link. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single navigation link.</param> /// <returns>Enumeration of test descriptors which will include the original navigation link in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > NavigationLinkPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataNestedResourceInfo navigationLink = testDescriptor.PayloadItems[0] as ODataNestedResourceInfo; Debug.Assert(navigationLink != null, "Link payload expected."); var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Single link on top-level entry { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry() }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Where(linkElement => linkElement.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value.StartsWith(TestAtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix)) .First()); }, }, // TODO: Add other interesting payloads for links - in expanded entry, in expanded feed }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
/// <summary> /// Writes the navigation link metadata. /// </summary> /// <param name="nestedResourceInfo">The navigation link to write the metadata for.</param> /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param> internal void WriteNavigationLinkMetadata(ODataNestedResourceInfo nestedResourceInfo, IDuplicatePropertyNameChecker duplicatePropertyNameChecker) { Debug.Assert(nestedResourceInfo != null, "nestedResourceInfo != null"); Debug.Assert(!string.IsNullOrEmpty(nestedResourceInfo.Name), "The nested resource info Name should have been validated by now."); Debug.Assert(duplicatePropertyNameChecker != null); Uri navigationLinkUrl = nestedResourceInfo.Url; string navigationLinkName = nestedResourceInfo.Name; Uri associationLinkUrl = nestedResourceInfo.AssociationLinkUrl; if (associationLinkUrl != null) { duplicatePropertyNameChecker.ValidatePropertyOpenForAssociationLink(navigationLinkName); this.WriteAssociationLink(nestedResourceInfo.Name, associationLinkUrl); } if (navigationLinkUrl != null) { // The navigation link URL is a property annotation "[email protected]: 'url'" this.ODataAnnotationWriter.WritePropertyAnnotationName(navigationLinkName, ODataAnnotationNames.ODataNavigationLinkUrl); this.JsonWriter.WriteValue(this.UriToString(navigationLinkUrl)); } }
/// <summary> /// Creates the navigation link for the given navigation property. /// </summary> /// <param name="entityToSerialize">Entity that is currently being serialized.</param> /// <param name="navigationProperty">The metadata for the navigation property.</param> /// <returns>The navigation link for the given property.</returns> private ODataNestedResourceInfo GetNavigationLink(EntityToSerialize entityToSerialize, ResourceProperty navigationProperty) { Debug.Assert(entityToSerialize != null, "entityToSerialize != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); string navLinkName = navigationProperty.Name; ODataNestedResourceInfo navLink = new ODataNestedResourceInfo { Name = navLinkName, IsCollection = navigationProperty.Kind == ResourcePropertyKind.ResourceSetReference }; // Always pass the relative uri to the ODatalib. For Json, they will convert the relative uri // into absolute uri using the BaseUri property on the ODataWriterSettings. For atom, ODataLib // will write the relative uri. this.PayloadMetadataPropertyManager.SetUrl(navLink, () => RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.RelativeEditLink, navLinkName)); if (this.Service.Configuration.DataServiceBehavior.IncludeAssociationLinksInResponse) { this.PayloadMetadataPropertyManager.SetAssociationLinkUrl(navLink, () => GetAssociationLinkUrl(entityToSerialize, navigationProperty)); } return(navLink); }
private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext context = null) { context = context ?? new TestMaterializerContext(); var resource = new ODataResource() { TypeName = "ComplexTypeWithChildComplexType", Properties = new ODataProperty[0] }; var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4); var materializerEntry = MaterializerEntry.CreateEntry(resource, ODataFormat.Json, false, clientEdmModel); materializerEntry.ResolvedObject = parentInstance; ODataNestedResourceInfo innerComplexP = new ODataNestedResourceInfo() { Name = "InnerComplexProperty", IsCollection = false }; MaterializerEntry innerMaterializerEntry; if (innerResource != null) { innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel); } else { innerMaterializerEntry = MaterializerEntry.CreateEmpty(); } MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry); materializerEntry.AddNestedResourceInfo(innerComplexP); var policy = this.CreateEntryMaterializationPolicy(context); policy.EntityTrackingAdapter.TargetInstance = parentInstance; policy.Materialize(materializerEntry, typeof(ComplexTypeWithChildComplexType), true); }
public void CallBaseWriteStart(ODataNestedResourceInfo navigationLink) { this.odataWriter.WriteStart(navigationLink); }
public void MultiBindingOnComplexWriterTest() { ODataResource topEntity = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "TopEntity" } } }; ODataNestedResourceInfo complex1Info = new ODataNestedResourceInfo() { Name = "complexProp1" }; ODataResource complex1 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "Prop1", Value = "complexProp1" } } }; ODataNestedResourceInfo complex2Info = new ODataNestedResourceInfo() { Name = "complexProp2" }; ODataResource complex2 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "Prop1", Value = "complexProp2" } } }; ODataNestedResourceInfo navOnComplexInfo = new ODataNestedResourceInfo() { Name = "CollectionOfNavOnComplex", IsCollection = true }; ODataResourceSet resourceSet = new ODataResourceSet(); ODataResource navEntity1 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity1" } } }; ODataResource navEntity2 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity2" } } }; string actual = WriteJsonLightEntry(Model, EntitySet, (writer) => { writer.WriteStart(topEntity); // complex1 and its navigation property writer.WriteStart(complex1Info); writer.WriteStart(complex1); writer.WriteStart(navOnComplexInfo); writer.WriteStart(resourceSet); writer.WriteStart(navEntity1); writer.WriteEnd(); writer.WriteStart(navEntity2); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); // complex2 and its navigation property writer.WriteStart(complex2Info); writer.WriteStart(complex2); writer.WriteStart(navOnComplexInfo); writer.WriteStart(resourceSet); writer.WriteStart(navEntity2); writer.WriteEnd(); writer.WriteStart(navEntity1); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); // end of top entity writer.WriteEnd(); }); Assert.Equal(complexPayload, actual); }
public void MultiBindingOnContainementWriterTest() { ODataResource topEntity = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "TopEntity" } } }; ODataNestedResourceInfo contained1Info = new ODataNestedResourceInfo() { Name = "ContainedNav1", IsCollection = false }; ODataResource contained1 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "ContainedNav1" } } }; ODataNestedResourceInfo contained2Info = new ODataNestedResourceInfo() { Name = "ContainedNav2", IsCollection = false }; ODataResource contained2 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "ContainedNav2" } } }; ODataNestedResourceInfo navOnContainedInfo = new ODataNestedResourceInfo() { Name = "NavOnContained", IsCollection = false }; ODataResource navEntity1 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity1" } } }; ODataResource navEntity2 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity2" } } }; string actual = WriteJsonLightEntry(Model, EntitySet, (writer) => { writer.WriteStart(topEntity); // contained1 and its navigation property writer.WriteStart(contained1Info); writer.WriteStart(contained1); writer.WriteStart(navOnContainedInfo); writer.WriteStart(navEntity1); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); // contained2 and its navigation property writer.WriteStart(contained2Info); writer.WriteStart(contained2); writer.WriteStart(navOnContainedInfo); writer.WriteStart(navEntity2); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); // end of top entity writer.WriteEnd(); }); Assert.Equal(containmentPayload, actual); }
public void MultiBindingOnComplexWithTypeCastWriterReaderTest() { ODataResource topEntity = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "TopEntity" } } }; ODataNestedResourceInfo complex1Info = new ODataNestedResourceInfo() { Name = "complexProp1" }; ODataResource complex1 = new ODataResource() { TypeName = "NS.DerivedComplexType", Properties = new[] { new ODataProperty { Name = "Prop1", Value = "complexProp1" }, new ODataProperty { Name = "DerivedProp", Value = "DerivedComplexProp" } } }; ODataNestedResourceInfo navOnComplexInfo = new ODataNestedResourceInfo() { Name = "CollectionOfNavOnComplex", IsCollection = true }; ODataResourceSet resourceSet = new ODataResourceSet(); ODataResource navEntity1 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity1" } } }; ODataResource navEntity2 = new ODataResource() { Properties = new[] { new ODataProperty { Name = "ID", Value = "NavEntity2" } } }; // Writer string actual = WriteJsonLightEntry(Model, EntitySet, (writer) => { writer.WriteStart(topEntity); // complex1 and its navigation property writer.WriteStart(complex1Info); writer.WriteStart(complex1); writer.WriteStart(navOnComplexInfo); writer.WriteStart(resourceSet); writer.WriteStart(navEntity1); writer.WriteEnd(); writer.WriteStart(navEntity2); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); writer.WriteEnd(); // end of top entity writer.WriteEnd(); }); string expected = "{" + "\"@odata.context\":\"http://host/$metadata#EntitySet/$entity\"," + "\"ID\":\"TopEntity\"," + "\"complexProp1\":{" + "\"@odata.type\":\"#NS.DerivedComplexType\"," + "\"Prop1\":\"complexProp1\"," + "\"DerivedProp\":\"DerivedComplexProp\"," + "\"CollectionOfNavOnComplex\":[" + "{\"ID\":\"NavEntity1\"}," + "{\"ID\":\"NavEntity2\"}]" + "}}"; Assert.Equal(expected, actual); // Reader var entryList = ReadPayload(expected, Model, EntitySet, EntityType); entryList[0].Id.Should().Be(new Uri("http://host/NavEntitySet1('NavEntity1')")); entryList[1].Id.Should().Be(new Uri("http://host/NavEntitySet1('NavEntity2')")); entryList[2].Id.Should().Be(null); entryList[2].TypeName.Should().Be("NS.DerivedComplexType"); entryList[3].Id.Should().Be(new Uri("http://host/EntitySet('TopEntity')")); }
/// <summary> /// Visits an item in the object model. /// </summary> /// <param name="objectModelItem">The item to visit.</param> public virtual T Visit(object objectModelItem) { ODataResourceSet feed = objectModelItem as ODataResourceSet; if (feed != null) { return(this.VisitFeed(feed)); } ODataResource entry = objectModelItem as ODataResource; if (entry != null) { return(this.VisitEntry(entry)); } ODataProperty property = objectModelItem as ODataProperty; if (property != null) { return(this.VisitProperty(property)); } ODataNestedResourceInfo navigationLink = objectModelItem as ODataNestedResourceInfo; if (navigationLink != null) { return(this.VisitNavigationLink(navigationLink)); } ODataResourceValue resourceValue = objectModelItem as ODataResourceValue; if (resourceValue != null) { return(this.VisitResourceValue(resourceValue)); } 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 is ODataPrimitiveValue || objectModelItem.GetType().IsValueType || objectModelItem is string || objectModelItem is byte[] || objectModelItem is ISpatial) { return(this.VisitPrimitiveValue(objectModelItem)); } if (objectModelItem is ODataUntypedValue) { object val = ODataObjectModelVisitor.ParseJsonToPrimitiveValue( (objectModelItem as ODataUntypedValue).RawValue); return(this.VisitPrimitiveValue(val)); } return(this.VisitUnsupportedValue(objectModelItem)); }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> protected abstract T VisitNavigationLink(ODataNestedResourceInfo navigationLink);
/// <summary> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="link"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="link">Property as parsed.</param> internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNestedResourceInfo link) { ValidatePropertyMatch(property, link, null, false /*performEntityCheck*/); }