public void InjectMetadataBuilderShouldNotSetBuilderOnEntryActions()
        {
            var entry = new ODataEntry();
            var builder = new TestEntityMetadataBuilder(entry);
            var action1 = new ODataAction { Metadata = new Uri("http://service/$metadata#action1", UriKind.Absolute) };
            var action2 = new ODataAction { Metadata = new Uri("http://service/$metadata#action2", UriKind.Absolute) };

            entry.AddAction(action1);
            entry.AddAction(action2);

            testSubject.InjectMetadataBuilder(entry, builder);
            action1.GetMetadataBuilder().Should().BeNull();
            action2.GetMetadataBuilder().Should().BeNull();
        }
        /// <summary>
        /// Creates the <see cref="ODataEntry"/> to be written while writing this entity.
        /// </summary>
        /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The created <see cref="ODataEntry"/>.</returns>
        public virtual ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
        {
            if (selectExpandNode == null)
            {
                throw Error.ArgumentNull("selectExpandNode");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            string typeName = entityInstanceContext.EntityType.FullName();

            ODataEntry entry = new ODataEntry
            {
                TypeName = typeName,
                Properties = CreateStructuralPropertyBag(selectExpandNode.SelectedStructuralProperties, entityInstanceContext),
            };

            // Try to add the dynamic properties if the entity type is open.
            if ((entityInstanceContext.EntityType.IsOpen && selectExpandNode.SelectAllDynamicProperties) ||
                (entityInstanceContext.EntityType.IsOpen && selectExpandNode.SelectedDynamicProperties.Any()))
            {
                IEdmTypeReference entityTypeReference =
                    entityInstanceContext.EntityType.ToEdmTypeReference(isNullable: false);
                List<ODataProperty> dynamicProperties = AppendDynamicProperties(entityInstanceContext.EdmObject,
                    (IEdmStructuredTypeReference)entityTypeReference,
                    entityInstanceContext.SerializerContext,
                    entry.Properties.ToList(),
                    selectExpandNode.SelectedDynamicProperties.ToArray());

                if (dynamicProperties != null)
                {
                    entry.Properties = entry.Properties.Concat(dynamicProperties);
                }
            }

            IEnumerable<ODataAction> actions = CreateODataActions(selectExpandNode.SelectedActions, entityInstanceContext);
            foreach (ODataAction action in actions)
            {
                entry.AddAction(action);
            }

            IEdmEntityType pathType = GetODataPathType(entityInstanceContext.SerializerContext);
            AddTypeNameAnnotationAsNeeded(entry, pathType, entityInstanceContext.SerializerContext.MetadataLevel);

            if (entityInstanceContext.NavigationSource != null)
            {
                if (!(entityInstanceContext.NavigationSource is IEdmContainedEntitySet))
                {
                    IEdmModel model = entityInstanceContext.SerializerContext.Model;
                    NavigationSourceLinkBuilderAnnotation linkBuilder = model.GetNavigationSourceLinkBuilder(entityInstanceContext.NavigationSource);
                    EntitySelfLinks selfLinks = linkBuilder.BuildEntitySelfLinks(entityInstanceContext, entityInstanceContext.SerializerContext.MetadataLevel);

                    if (selfLinks.IdLink != null)
                    {
                        entry.Id = selfLinks.IdLink;
                    }

                    if (selfLinks.ReadLink != null)
                    {
                        entry.ReadLink = selfLinks.ReadLink;
                    }

                    if (selfLinks.EditLink != null)
                    {
                        entry.EditLink = selfLinks.EditLink;
                    }
                }

                string etag = CreateETag(entityInstanceContext);
                if (etag != null)
                {
                    entry.ETag = etag;
                }
            }

            return entry;
        }
        public void InjectMetadataBuilderShouldSetBuilderOnEntryActions()
        {
            var entry = new ODataEntry();
            var builder = new TestEntityMetadataBuilder(entry);
            var action1 = new ODataAction { Metadata = new Uri(MetadataDocumentUri, "#action1") };
            var action2 = new ODataAction { Metadata = new Uri(MetadataDocumentUri, "#action2") };

            entry.AddAction(action1);
            entry.AddAction(action2);

            testSubject.InjectMetadataBuilder(entry, builder);
            action1.GetMetadataBuilder().Should().BeSameAs(builder);
            action2.GetMetadataBuilder().Should().BeSameAs(builder);
        }
        /// <summary>
        /// Creates the <see cref="ODataEntry"/> to be written while writing this entity.
        /// </summary>
        /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The created <see cref="ODataEntry"/>.</returns>
        public virtual ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
        {
            if (selectExpandNode == null)
            {
                throw Error.ArgumentNull("selectExpandNode");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            string typeName = entityInstanceContext.EntityType.FullName();

            ODataEntry entry = new ODataEntry
            {
                TypeName = typeName,
                Properties = CreateStructuralPropertyBag(selectExpandNode.SelectedStructuralProperties, entityInstanceContext),
            };

            IEnumerable<ODataAction> actions = CreateODataActions(selectExpandNode.SelectedActions, entityInstanceContext);
            foreach (ODataAction action in actions)
            {
                entry.AddAction(action);
            }

            IEdmEntityType pathType = GetODataPathType(entityInstanceContext.SerializerContext);
            AddTypeNameAnnotationAsNeeded(entry, pathType, entityInstanceContext.SerializerContext.MetadataLevel);

            if (entityInstanceContext.NavigationSource != null)
            {
                if (!(entityInstanceContext.NavigationSource is IEdmContainedEntitySet))
                {
                    IEdmModel model = entityInstanceContext.SerializerContext.Model;
                    NavigationSourceLinkBuilderAnnotation linkBuilder = model.GetNavigationSourceLinkBuilder(entityInstanceContext.NavigationSource);
                    EntitySelfLinks selfLinks = linkBuilder.BuildEntitySelfLinks(entityInstanceContext, entityInstanceContext.SerializerContext.MetadataLevel);

                    if (selfLinks.IdLink != null)
                    {
                        entry.Id = selfLinks.IdLink;
                    }

                    if (selfLinks.ReadLink != null)
                    {
                        entry.ReadLink = selfLinks.ReadLink;
                    }

                    if (selfLinks.EditLink != null)
                    {
                        entry.EditLink = selfLinks.EditLink;
                    }
                }

                string etag = CreateETag(entityInstanceContext);
                if (etag != null)
                {
                    entry.ETag = etag;
                }
            }

            return entry;
        }
 public void ShouldWriteActionForRequestEntryPayloadWithUserModel()
 {
     ODataEntry entry = new ODataEntry { TypeName = "NS.MyDerivedEntityType" };
     entry.AddAction(new ODataAction { Metadata = new Uri("#Action1", UriKind.Relative) });
     const string expectedPayload = "{\"@odata.type\":\"#NS.MyDerivedEntityType\",\"#Action1\":{}}";
     Action action = () => this.WriteNestedItemsAndValidatePayload(entitySet: null, entityType: null, nestedItemToWrite: new[] { entry }, expectedPayload: expectedPayload, writingResponse: false);
     action.ShouldThrow<ODataException>().WithMessage(Strings.WriterValidationUtils_OperationInRequest("#Action1"));
 }
 public void ShouldWriteActionForResponseEntryPayloadWithUserModel()
 {
     ODataEntry entry = new ODataEntry { TypeName = "NS.MyDerivedEntityType" };
     entry.AddAction(new ODataAction { Metadata = new Uri("#Action1", UriKind.Relative) });
     const string expectedPayload = "{\"@odata.context\":\"http://odata.org/test/$metadata#MySet/$entity\",\"@odata.type\":\"#NS.MyDerivedEntityType\",\"#Action1\":{}}";
     this.WriteNestedItemsAndValidatePayload(entitySet: this.entitySet, entityType: null, nestedItemToWrite: new[] { entry }, expectedPayload: expectedPayload, writingResponse: true);
 }
        public void ActionAndFunctionPayloadOrderTest()
        {
            EdmModel model = new EdmModel();
            var container = new EdmEntityContainer("TestModel", "TestContainer");
            model.AddElement(container);

            var otherType = new EdmEntityType("TestModel", "OtherType");
            otherType.AddKeys(otherType.AddStructuralProperty("ID", EdmCoreModel.Instance.GetInt32(false)));
            model.AddElement(otherType);
            container.AddEntitySet("OtherType", otherType);

            var nonMLEBaseType = new EdmEntityType("TestModel", "NonMLEBaseType");
            nonMLEBaseType.AddKeys(nonMLEBaseType.AddStructuralProperty("ID", EdmCoreModel.Instance.GetInt32(false)));
            model.AddElement(nonMLEBaseType);
            var nonMLESet = container.AddEntitySet("NonMLESet", nonMLEBaseType);

            var nonMLEType = new EdmEntityType("TestModel", "NonMLEType", nonMLEBaseType);
            nonMLEType.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(true));
            nonMLEType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "NavProp", Target = otherType, TargetMultiplicity = EdmMultiplicity.Many });
            model.AddElement(nonMLEType);
            container.AddEntitySet("NonMLEType", nonMLEType);

            ODataAction action = new ODataAction
            {
                Metadata = new Uri("http://odata.org/test/$metadata#defaultAction"),
                Title = "Default Action",
                Target = new Uri("http://www.odata.org/defaultAction"),
            };

            ODataFunction function = new ODataFunction
            {
                Metadata = new Uri("http://odata.org/test/$metadata#defaultFunction()"),
                Title = "Default Function",
                Target = new Uri("defaultFunctionTarget", UriKind.Relative)
            };

            string defaultJson = string.Join("$(NL)",
                "{{",
                "{1}" +
                "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + "\":\"#TestModel.NonMLEType\"{0},\"#defaultAction\":{{",
                "\"title\":\"Default Action\",\"target\":\"http://www.odata.org/defaultAction\"",
                "}},\"#defaultFunction()\":{{",
                "\"title\":\"Default Function\",\"target\":\"defaultFunctionTarget\"",
                "}}",
                "}}");

            var entryWithActionAndFunction = new ODataEntry() { TypeName = "TestModel.NonMLEType", };
            entryWithActionAndFunction.AddAction(action);
            entryWithActionAndFunction.AddFunction(function);
            IEnumerable<EntryPayloadTestCase> testCases = new[]
            {
                new EntryPayloadTestCase
                {
                    DebugDescription = "Functions and actions available at the beginning.",
                    Entry = entryWithActionAndFunction,
                    Model = model,
                    EntitySet = nonMLESet,
                    Json = defaultJson
                },
            };

            IEnumerable<PayloadWriterTestDescriptor<ODataItem>> testDescriptors = testCases.Select(testCase =>
                new PayloadWriterTestDescriptor<ODataItem>(
                    this.Settings,
                    new ODataItem[] { testCase.Entry },
                    tc => new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                    {
                        Json = string.Format(CultureInfo.InvariantCulture, testCase.Json,
                            string.Empty,
                            tc.IsRequest ? string.Empty : (JsonLightWriterUtils.GetMetadataUrlPropertyForEntry(testCase.EntitySet.Name) + ",")),
                        FragmentExtractor = (result) => result.RemoveAllAnnotations(true)
                    })
                {
                    DebugDescription = testCase.DebugDescription,
                    Model = testCase.Model,
                    PayloadEdmElementContainer = testCase.EntitySet,
                    PayloadEdmElementType = testCase.EntityType,
                    SkipTestConfiguration = testCase.SkipTestConfiguration
                });

            testDescriptors = testDescriptors.Concat(testCases.Select(testCase =>
                new PayloadWriterTestDescriptor<ODataItem>(
                    this.Settings,
                    new ODataItem[] { testCase.Entry, new ODataNavigationLink
                    {
                        Name = "NavProp",
                        IsCollection = true,
                        Url = new Uri("http://odata.org/navprop/uri")
                    }},
                    tc => new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                    {
                        Json = string.Format(CultureInfo.InvariantCulture, testCase.Json,
                            tc.IsRequest ?
                                ",\"NavProp\":[$(NL){$(NL)\"__metadata\":{$(NL)\"uri\":\"http://odata.org/navprop/uri\"$(NL)}$(NL)}$(NL)]" :
                                ",\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + "\":\"http://odata.org/navprop/uri\"",
                                tc.IsRequest ? string.Empty : (JsonLightWriterUtils.GetMetadataUrlPropertyForEntry(testCase.EntitySet.Name) + ",")),
                        FragmentExtractor = (result) => result.RemoveAllAnnotations(true)
                    })
                {
                    DebugDescription = testCase.DebugDescription + "- with navigation property",
                    Model = testCase.Model,
                    PayloadEdmElementContainer = testCase.EntitySet,
                    PayloadEdmElementType = testCase.EntityType,
                    SkipTestConfiguration = testCase.SkipTestConfiguration
                }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors,
                // Actions/functions are only supported in responses.
                this.WriterTestConfigurationProvider.JsonLightFormatConfigurationsWithIndent.Where(tc => !tc.IsRequest),
                (testDescriptor, testConfiguration) =>
                {
                    TestWriterUtils.WriteAndVerifyODataEdmPayload(testDescriptor.DeferredLinksToEntityReferenceLinksInRequest(testConfiguration), testConfiguration, this.Assert, this.Logger);
                });
        }
示例#8
0
        /// <summary>Write the entry element.</summary>
        /// <param name="expanded">Expanded result provider for the specified <paramref name="element"/>.</param>
        /// <param name="element">Element representing the entry element.</param>
        /// <param name="resourceInstanceInFeed">true if the resource instance being serialized is inside a feed; false otherwise.</param>
        /// <param name="expectedType">Expected type of the entry element.</param>
        private void WriteEntry(IExpandedResult expanded, object element, bool resourceInstanceInFeed, ResourceType expectedType)
        {
            Debug.Assert(element != null, "element != null");
            Debug.Assert(expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType, "expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType");
            this.IncrementSegmentResultCount();

            ODataEntry entry = new ODataEntry();
            if (!resourceInstanceInFeed)
            {
                entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = this.CurrentContainer.Name, NavigationSourceEntityTypeName = this.CurrentContainer.ResourceType.FullName, ExpectedTypeName = expectedType.FullName });
            }

            string title = expectedType.Name;
#pragma warning disable 618
            if (this.contentFormat == ODataFormat.Atom)
#pragma warning restore 618
            {
                AtomEntryMetadata entryAtom = new AtomEntryMetadata();
                entryAtom.EditLink = new AtomLinkMetadata { Title = title };
                entry.SetAnnotation(entryAtom);
            }

            ResourceType actualResourceType = WebUtil.GetNonPrimitiveResourceType(this.Provider, element);
            if (actualResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)
            {
                // making sure that the actual resource type is an entity type
                throw new DataServiceException(500, Microsoft.OData.Service.Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(actualResourceType.FullName));
            }

            EntityToSerialize entityToSerialize = this.WrapEntity(element, actualResourceType);

            // populate the media resource, if the entity is a MLE.
            entry.MediaResource = this.GetMediaResource(entityToSerialize, title);

            // Write the type name
            this.PayloadMetadataPropertyManager.SetTypeName(entry, this.CurrentContainer.ResourceType.FullName, actualResourceType.FullName);

            // Write Id element
            this.PayloadMetadataPropertyManager.SetId(entry, () => entityToSerialize.SerializedKey.Identity);

            // Write "edit" link
            this.PayloadMetadataPropertyManager.SetEditLink(entry, () => entityToSerialize.SerializedKey.RelativeEditLink);

            // Write the etag property, if the type has etag properties
            this.PayloadMetadataPropertyManager.SetETag(entry, () => this.GetETagValue(element, actualResourceType));
            
            IEnumerable<ProjectionNode> projectionNodes = this.GetProjections();
            if (projectionNodes != null)
            {
                // Filter the projection nodes for the actual type of the entity
                // The projection node might refer to the property in a derived type. If the TargetResourceType of
                // the projection node is not a super type, then we do not want to serialize this property.
                projectionNodes = projectionNodes.Where(projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(actualResourceType));

                // Because we are going to enumerate through these multiple times, create a list.
                projectionNodes = projectionNodes.ToList();

                // And add the annotation to tell ODataLib which properties to write into content (the projections)
                entry.SetAnnotation(new ProjectedPropertiesAnnotation(projectionNodes.Select(p => p.PropertyName)));
            }

            // Populate the advertised actions
            IEnumerable<ODataAction> actions;
            if (this.TryGetAdvertisedActions(entityToSerialize, resourceInstanceInFeed, out actions))
            {
                foreach (ODataAction action in actions)
                {
                    entry.AddAction(action);
                }
            }

            // Populate all the normal properties
            entry.Properties = this.GetEntityProperties(entityToSerialize, projectionNodes);

            // And start the entry
            var args = new DataServiceODataWriterEntryArgs(entry, element, this.Service.OperationContext);
            this.dataServicesODataWriter.WriteStart(args);

            // Now write all the navigation properties
            this.WriteNavigationProperties(expanded, entityToSerialize, resourceInstanceInFeed, projectionNodes);

            // And write the end of the entry
            this.dataServicesODataWriter.WriteEnd(args);

#if ASTORIA_FF_CALLBACKS
            this.Service.InternalOnWriteItem(target, element);
#endif
        }
        public void NoOpMetadataBuilderShouldReturnActionsSetByUser()
        {
            ODataAction action = new ODataAction()
            {
                Metadata = new Uri("http://example.com/$metadata#Action"),
                Target = new Uri("http://example.com/Action"),
                Title = "ActionTitle"
            };

            ODataEntry entry = new ODataEntry();
            entry.AddAction(action);
            new NoOpEntityMetadataBuilder(entry).GetActions()
                .Should().ContainSingle(a => a == action);
            
            // Verify that the action information wasn't removed or changed.
            action.Metadata.Should().Be(new Uri("http://example.com/$metadata#Action"));
            action.Target.Should().Be(new Uri("http://example.com/Action"));
            action.Title.Should().Be("ActionTitle");
        }