public void NoOpMetadataBuilderShouldReturnMediaResourceSetByUser()
        {
            var mediaResource = new ODataStreamReferenceValue
                {
                    ContentType = "image/jpeg",
                    EditLink = new Uri("http://example.com/stream/edit"),
                    ReadLink = new Uri("http://example.com/stream/read"),
                    ETag = "stream etag"
                };

            new NoOpEntityMetadataBuilder(new ODataEntry { MediaResource = mediaResource }).GetMediaResource()
                .Should().Be(mediaResource);
        }
 public void InjectMetadataBuilderShouldNotSetBuilderOnEntryNamedStreamProperties()
 {
     var entry = new ODataEntry();
     var builder = new TestEntityMetadataBuilder(entry);
     var stream1 = new ODataStreamReferenceValue();
     var stream2 = new ODataStreamReferenceValue();
     entry.Properties = new[]
         {
             new ODataProperty {Name = "Stream1", Value = stream1},
             new ODataProperty {Name = "Stream2", Value = stream2}
         };
     testSubject.InjectMetadataBuilder(entry, builder);
     stream1.GetMetadataBuilder().Should().BeNull();
     stream2.GetMetadataBuilder().Should().BeNull();
 }
        public ODataStreamReferenceValueTests()
        {
            this.testSubject = new ODataStreamReferenceValue();

            var entry = new ODataEntry
            {
                TypeName = "ns.DerivedType",
                Properties = new[]
                {
                    new ODataProperty{Name = "Id", Value = 1, SerializationInfo = new ODataPropertySerializationInfo{PropertyKind = ODataPropertyKind.Key}},
                    new ODataProperty{Name = "Name", Value = "Bob", SerializationInfo = new ODataPropertySerializationInfo{PropertyKind = ODataPropertyKind.ETag}}
                }
            };

            var serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.BaseType", ExpectedTypeName = "ns.BaseType" };
            var typeContext = ODataFeedAndEntryTypeContext.Create(serializationInfo, null, null, null, EdmCoreModel.Instance, true);
            var metadataContext = new TestMetadataContext();
            var entryMetadataContext = ODataEntryMetadataContext.Create(entry, typeContext, serializationInfo, null, metadataContext, SelectedPropertiesNode.EntireSubtree);
            var fullMetadataBuilder = new ODataConventionalEntityMetadataBuilder(entryMetadataContext, metadataContext, new ODataConventionalUriBuilder(ServiceUri, UrlConvention.CreateWithExplicitValue(false)));
            this.streamWithFullBuilder = new ODataStreamReferenceValue();
            this.streamWithFullBuilder.SetMetadataBuilder(fullMetadataBuilder, "Stream");
        }
示例#4
0
 private void ReadContentTypeMetadataProperty(ref ODataJsonReaderUtils.MetadataPropertyBitMask metadataPropertiesFoundBitField, ref ODataStreamReferenceValue mediaResource)
 {
     if (base.UseServerFormatBehavior)
     {
         base.JsonReader.SkipValue();
     }
     else
     {
         ODataJsonReaderUtils.VerifyMetadataPropertyNotFound(ref metadataPropertiesFoundBitField, ODataJsonReaderUtils.MetadataPropertyBitMask.ContentType, "content_type");
         ODataJsonReaderUtils.EnsureInstance <ODataStreamReferenceValue>(ref mediaResource);
         string propertyValue = base.JsonReader.ReadStringValue("content_type");
         ODataJsonReaderUtils.ValidateMetadataStringProperty(propertyValue, "content_type");
         mediaResource.ContentType = propertyValue;
     }
 }
 /// <summary>
 /// Visits a stream reference value (named stream).
 /// </summary>
 /// <param name="streamReferenceValue">The stream reference value to visit.</param>
 protected override void VisitStreamReferenceValue(ODataStreamReferenceValue streamReferenceValue)
 {
     this.ValidateUri(streamReferenceValue.EditLink);
     this.ValidateUri(streamReferenceValue.ReadLink);
     base.VisitStreamReferenceValue(streamReferenceValue);
 }
示例#6
0
        /// <summary>
        /// Updates the entity descriptor.
        /// </summary>
        public void UpdateEntityDescriptor()
        {
            if (!this.EntityDescriptorUpdated)
            {
                // Named stream properties are represented on the result type as a DataServiceStreamLink, which contains the
                // ReadLink and EditLink for the stream. We need to build this metadata information even with NoTracking,
                // because it is exposed on the result instances directly, not just in the context.
                foreach (ODataProperty property in this.Properties)
                {
                    ODataStreamReferenceValue streamValue = property.Value as ODataStreamReferenceValue;
                    if (streamValue != null)
                    {
                        StreamDescriptor streamInfo = this.EntityDescriptor.AddStreamInfoIfNotPresent(property.Name);

                        if (streamValue.ReadLink != null)
                        {
                            streamInfo.SelfLink = streamValue.ReadLink;
                        }

                        if (streamValue.EditLink != null)
                        {
                            streamInfo.EditLink = streamValue.EditLink;
                        }

                        streamInfo.ETag = streamValue.ETag;

                        streamInfo.ContentType = streamValue.ContentType;
                    }
                }

                // We need this to be populated as well for entities that may contain this
                if (this.entry.MediaResource != null)
                {
                    if (this.entry.MediaResource.ReadLink != null)
                    {
                        this.EntityDescriptor.ReadStreamUri = this.entry.MediaResource.ReadLink;
                    }

                    if (this.entry.MediaResource.EditLink != null)
                    {
                        this.EntityDescriptor.EditStreamUri = this.entry.MediaResource.EditLink;
                    }

                    if (this.entry.MediaResource.ETag != null)
                    {
                        this.EntityDescriptor.StreamETag = this.entry.MediaResource.ETag;
                    }
                }

                if (this.IsTracking)
                {
                    this.EntityDescriptor.Identity = this.entry.Id;
                    this.EntityDescriptor.EditLink = this.entry.EditLink;
                    this.EntityDescriptor.SelfLink = this.entry.ReadLink;
                    this.EntityDescriptor.ETag     = this.entry.ETag;

                    if (this.entry.Functions != null)
                    {
                        foreach (ODataFunction function in this.entry.Functions)
                        {
                            this.EntityDescriptor.AddOperationDescriptor(new FunctionDescriptor {
                                Title = function.Title, Metadata = function.Metadata, Target = function.Target
                            });
                        }
                    }

                    if (this.entry.Actions != null)
                    {
                        foreach (ODataAction action in this.entry.Actions)
                        {
                            this.EntityDescriptor.AddOperationDescriptor(new ActionDescriptor {
                                Title = action.Title, Metadata = action.Metadata, Target = action.Target
                            });
                        }
                    }
                }

                this.EntityDescriptorUpdated = true;
            }
        }
        /// <summary>
        /// Sets specified media resource on an entry and hooks up metadata builder.
        /// </summary>
        /// <param name="entryState">The entry state to use.</param>
        /// <param name="mediaResource">The media resource to set.</param>
        private void SetEntryMediaResource(IODataJsonLightReaderEntryState entryState, ODataStreamReferenceValue mediaResource)
        {
            Debug.Assert(entryState != null, "entryState != null");
            Debug.Assert(mediaResource != null, "mediaResource != null");
            ODataEntry entry = entryState.Entry;
            Debug.Assert(entry != null, "entry != null");

            ODataEntityMetadataBuilder builder = this.MetadataContext.GetEntityMetadataBuilderForReader(entryState, this.JsonLightInputContext.MessageReaderSettings.UseKeyAsSegment);
            mediaResource.SetMetadataBuilder(builder, /*propertyName*/ null);
            entry.MediaResource = mediaResource;
        }
        /// <summary>
        /// Returns an existing stream property value if it already exists in the list of OData properties otherwise creates a new 
        /// ODataProperty for the stream property and returns the value of that property.
        /// </summary>
        /// <param name="entryState">The reader entry state for the entry being read.</param>
        /// <param name="streamPropertyName">The name of the stream property to return.</param>
        /// <returns>A new or an existing stream property value.</returns>
        private ODataStreamReferenceValue GetNewOrExistingStreamPropertyValue(IODataAtomReaderEntryState entryState, string streamPropertyName)
        {
            Debug.Assert(entryState != null, "entryState != null");
            Debug.Assert(streamPropertyName != null, "streamPropertyName != null");

            ReadOnlyEnumerable<ODataProperty> properties = entryState.Entry.Properties.ToReadOnlyEnumerable("Properties");

            // Property names are case sensitive, so compare in a case sensitive way.
            ODataProperty streamProperty = properties.FirstOrDefault(p => String.CompareOrdinal(p.Name, streamPropertyName) == 0);

            ODataStreamReferenceValue streamReferenceValue;
            if (streamProperty == null)
            {
                // The ValidateLinkPropertyDefined will fail if a stream property is not defined and the reader settings don't allow
                // reporting undeclared link properties. So if the method returns null, it means report the undeclared property anyway.
                IEdmProperty streamEdmProperty = ReaderValidationUtils.ValidateLinkPropertyDefined(streamPropertyName, entryState.EntityType, this.MessageReaderSettings);

                streamReferenceValue = new ODataStreamReferenceValue();
                streamProperty = new ODataProperty
                {
                    Name = streamPropertyName,
                    Value = streamReferenceValue
                };

                ReaderValidationUtils.ValidateStreamReferenceProperty(streamProperty, entryState.EntityType, streamEdmProperty, this.MessageReaderSettings);
                entryState.DuplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty);
                properties.AddToSourceList(streamProperty);
            }
            else
            {
                streamReferenceValue = streamProperty.Value as ODataStreamReferenceValue;
                if (streamReferenceValue == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataAtomEntryAndFeedDeserializer_StreamPropertyDuplicatePropertyName(streamPropertyName));
                }
            }

            return streamReferenceValue;
        }
        /// <summary>
        /// Computes all projected or missing stream properties.
        /// </summary>
        /// <param name="nonComputedProperties">Non-computed properties from the entity.</param>
        /// <returns>The the computed stream properties for the entry.</returns>
        private IEnumerable<ODataProperty> GetComputedStreamProperties(IEnumerable<ODataProperty> nonComputedProperties)
        {
            if (this.computedStreamProperties == null)
            {
                // Remove all the projected properties that were already read from the payload
                IDictionary<string, IEdmStructuralProperty> projectedStreamProperties = this.entryMetadataContext.SelectedStreamProperties;
                if (nonComputedProperties != null)
                {
                    foreach (ODataProperty payloadProperty in nonComputedProperties)
                    {
                        projectedStreamProperties.Remove(payloadProperty.Name);
                    }
                }

                this.computedStreamProperties = new List<ODataProperty>();
                if (projectedStreamProperties.Count > 0)
                {
                    // Create all the missing stream properties and set the metadata builder
                    foreach (string missingStreamPropertyName in projectedStreamProperties.Keys)
                    {
                        ODataStreamReferenceValue streamPropertyValue = new ODataStreamReferenceValue();
                        streamPropertyValue.SetMetadataBuilder(this, missingStreamPropertyName);
                        this.computedStreamProperties.Add(new ODataProperty { Name = missingStreamPropertyName, Value = streamPropertyValue });
                    }
                }
            }

            return this.computedStreamProperties;
        }
        private void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            bool allowStreamProperty,
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
            WriterValidationUtils.ValidatePropertyNotNull(property);

            string propertyName = property.Name;

            if (!this.JsonLightOutputContext.PropertyCacheHandler.InResourceSetScope())
            {
                WriterValidationUtils.ValidatePropertyName(propertyName);
                this.currentPropertyInfo = new PropertySerializationInfo(propertyName, owningType)
                {
                    IsTopLevel = isTopLevel
                };
            }
            else
            {
                this.currentPropertyInfo = this.JsonLightOutputContext.PropertyCacheHandler.GetProperty(propertyName, owningType);
            }

            WriterValidationUtils.ValidatePropertyDefined(this.currentPropertyInfo, this.MessageWriterSettings.ThrowOnUndeclaredPropertyForNonOpenType);

            duplicatePropertyNameChecker.ValidatePropertyUniqueness(property);

            if (currentPropertyInfo.MetadataType.IsUndeclaredProperty)
            {
                WriteODataTypeAnnotation(property, isTopLevel);
            }

            WriteInstanceAnnotation(property, isTopLevel, currentPropertyInfo.MetadataType.IsUndeclaredProperty);

            ODataValue value = property.ODataValue;

            // handle ODataUntypedValue
            ODataUntypedValue untypedValue = value as ODataUntypedValue;

            if (untypedValue != null)
            {
                WriteUntypedValue(untypedValue);
                return;
            }

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null)
            {
                if (!allowStreamProperty)
                {
                    throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataResource(propertyName));
                }

                Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type.");
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriterValidationUtils.ValidateStreamReferenceProperty(property, currentPropertyInfo.MetadataType.EdmProperty, this.WritingResponse);
                this.WriteStreamReferenceProperty(propertyName, streamReferenceValue);
                return;
            }

            if (value is ODataNullValue || value == null)
            {
                this.WriteNullProperty(property);
                return;
            }

            bool isOpenPropertyType = this.IsOpenProperty(property);

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                this.WritePrimitiveProperty(primitiveValue, isOpenPropertyType);
                return;
            }

            ODataEnumValue enumValue = value as ODataEnumValue;

            if (enumValue != null)
            {
                this.WriteEnumProperty(enumValue, isOpenPropertyType);
                return;
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                this.WriteCollectionProperty(collectionValue, isOpenPropertyType);
                return;
            }
        }
示例#11
0
        private void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            bool allowStreamProperty,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            WriterValidationUtils.ValidatePropertyNotNull(property);

            string propertyName = property.Name;

            if (projectedProperties.ShouldSkipProperty(propertyName))
            {
                return;
            }

            WriterValidationUtils.ValidatePropertyName(propertyName, bypassValidation);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);

            if (property.InstanceAnnotations.Any())
            {
                if (isTopLevel)
                {
                    this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations);
                }
                else
                {
                    this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations, propertyName);
                }
            }

            IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(
                propertyName,
                owningType,
                !this.bypassValidation);
            IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type;

            ODataValue value = property.ODataValue;

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null)
            {
                if (!allowStreamProperty)
                {
                    throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                }

                Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type.");
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.WritingResponse, this.bypassValidation);
                this.WriteStreamReferenceProperty(propertyName, streamReferenceValue);
                return;
            }

            string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName;

            if (value is ODataNullValue || value == null)
            {
                WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model, this.bypassValidation);

                if (isTopLevel)
                {
                    // Write the special null marker for top-level null properties.
                    this.ODataAnnotationWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull);
                    this.JsonWriter.WriteValue(true);
                }
                else
                {
                    this.JsonWriter.WriteName(wirePropertyName);
                    this.JsonLightValueSerializer.WriteNullValue();
                }

                return;
            }

            bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty);

            if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation)
            {
                ValidationUtils.ValidateOpenPropertyValue(propertyName, value);
            }

            ODataComplexValue complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                if (!isTopLevel)
                {
                    this.JsonWriter.WriteName(wirePropertyName);
                }

                this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker());
                return;
            }

            IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType);
            ODataEnumValue    enumValue     = value as ODataEnumValue;

            if (enumValue != null)
            {
                // This is a work around, needTypeOnWire always = true for client side:
                // ClientEdmModel's reflection can't know a property is open type even if it is, so here
                // make client side always write 'odata.type' for enum.
                bool   needTypeOnWire  = string.Equals(this.JsonLightOutputContext.Model.GetType().Name, "ClientEdmModel", StringComparison.OrdinalIgnoreCase);
                string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(
                    enumValue, propertyTypeReference, typeFromValue, needTypeOnWire ? true /* leverage this flag to write 'odata.type' */ : isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);
                this.JsonWriter.WriteName(wirePropertyName);
                this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference);
                return;
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel);
                this.JsonWriter.WriteName(wirePropertyName);

                // passing false for 'isTopLevel' because the outer wrapping object has already been written.
                this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType);
            }
            else
            {
                ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;
                Debug.Assert(primitiveValue != null, "primitiveValue != null");

                string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);

                this.JsonWriter.WriteName(wirePropertyName);
                this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference);
            }
        }
示例#12
0
        private void WriteValue(object value)
        {
            ODataComplexValue complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                this.writer.WriteLine("ODataComplexValue");
                this.writer.Indent++;
                this.writer.WriteLine("TypeName: " + (complexValue.TypeName ?? "<null>"));
                this.WriteProperties(complexValue.Properties);
                this.writer.Indent--;

                return;
            }

            ODataMultiValue multiValue = value as ODataMultiValue;

            if (multiValue != null)
            {
                this.writer.WriteLine("ODataMultiValue");
                this.writer.Indent++;
                this.writer.WriteLine("TypeName: " + (multiValue.TypeName ?? "<null>"));
                this.writer.WriteLine("Items:");
                this.writer.Indent++;
                foreach (object item in multiValue.Items)
                {
                    this.WriteValue(item);
                }

                this.writer.Indent--;
                this.writer.Indent--;

                return;
            }

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null)
            {
                this.writer.WriteLine("ODataStreamReferenceValue");
                this.writer.Indent++;
                if (streamReferenceValue.ReadLink != null)
                {
                    this.writer.WriteLine("ReadLink: " + streamReferenceValue.ReadLink.AbsoluteUri);
                }

                if (streamReferenceValue.EditLink != null)
                {
                    this.writer.WriteLine("EditLink: " + streamReferenceValue.EditLink.AbsoluteUri);
                }

                this.writer.Indent--;

                return;
            }

            if (value == null)
            {
                this.writer.WriteLine("null");
            }
            else
            {
                this.writer.WriteLine(value.ToString());
            }
        }
示例#13
0
        public void NamedStreamReadAndEditLinkMetadataWriterTest()
        {
            Func <XElement, XElement> fragmentExtractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + "link").Last();

            var allTestCases = linkMetadataTestCases.ConcatSingle(incorrectMediaTypeLinkMetadataTestCases).ConcatSingle(incorrectTitleLinkMetadataTestCases);

            var readLinkTestDescriptors = allTestCases.Select(testCase =>
            {
                ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                ODataStreamReferenceValue streamReferenceValue = new ODataStreamReferenceValue()
                {
                    ReadLink    = new Uri(readLinkHref),
                    ContentType = linkMediaType,
                };

                AtomStreamReferenceMetadata streamReferenceMetadata = new AtomStreamReferenceMetadata()
                {
                    SelfLink = testCase.LinkMetadata("http://docs.oasis-open.org/odata/ns/mediaresource/Stream", readLinkHref)
                };

                streamReferenceValue.SetAnnotation <AtomStreamReferenceMetadata>(streamReferenceMetadata);
                entry.Properties = new ODataProperty[]
                {
                    new ODataProperty {
                        Name = "Id", Value = 1
                    },
                    new ODataProperty {
                        Name = "Stream", Value = streamReferenceValue
                    }
                };

                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.ExpectedXml == null ? null : testCase.ExpectedXml("http://docs.oasis-open.org/odata/ns/mediaresource/Stream", readLinkHref, "Stream", linkMediaType),
                    ExpectedException2 = testCase.ExpectedException == null ? null : testCase.ExpectedException("http://docs.oasis-open.org/odata/ns/mediaresource/Stream", readLinkHref),
                    FragmentExtractor = fragmentExtractor
                }));
            });

            var editLinkTestDescriptors = allTestCases.Select(testCase =>
            {
                ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
                ODataStreamReferenceValue streamReferenceValue = new ODataStreamReferenceValue()
                {
                    ReadLink    = new Uri(readLinkHref),
                    EditLink    = new Uri(editLinkHref),
                    ContentType = linkMediaType,
                };

                AtomStreamReferenceMetadata streamReferenceMetadata = new AtomStreamReferenceMetadata()
                {
                    EditLink = testCase.LinkMetadata("http://docs.oasis-open.org/odata/ns/edit-media/Stream", editLinkHref)
                };

                streamReferenceValue.SetAnnotation <AtomStreamReferenceMetadata>(streamReferenceMetadata);
                entry.Properties = new ODataProperty[]
                {
                    new ODataProperty {
                        Name = "Id", Value = 1
                    },
                    new ODataProperty {
                        Name = "Stream", Value = streamReferenceValue
                    }
                };

                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.ExpectedXml == null ? null : testCase.ExpectedXml("http://docs.oasis-open.org/odata/ns/edit-media/Stream", editLinkHref, "Stream", linkMediaType),
                    ExpectedException2 = testCase.ExpectedException == null ? null : testCase.ExpectedException("http://docs.oasis-open.org/odata/ns/edit-media/Stream", editLinkHref),
                    FragmentExtractor = fragmentExtractor
                }));
            });

            var testDescriptors = readLinkTestDescriptors.Concat(editLinkTestDescriptors);

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations
                .Where(tc => !tc.IsRequest),
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
示例#14
0
 /// <summary>
 /// Visits a stream reference value (named stream).
 /// </summary>
 /// <param name="streamReferenceValue">The stream reference value to visit.</param>
 protected virtual void VisitStreamReferenceValue(ODataStreamReferenceValue streamReferenceValue)
 {
 }
示例#15
0
        /// <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 is ODataPrimitiveValue || 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);
        }
        internal override ODataStreamReferenceValue GetMediaResource()
        {
            if (this.entryMetadataContext.Entry.NonComputedMediaResource != null)
            {
                return this.entryMetadataContext.Entry.NonComputedMediaResource;
            }

            if (this.computedMediaResource == null && this.entryMetadataContext.TypeContext.IsMediaLinkEntry)
            {
                this.computedMediaResource = new ODataStreamReferenceValue();
                this.computedMediaResource.SetMetadataBuilder(this, /*propertyName*/ null);
            }

            return this.computedMediaResource;
        }
示例#17
0
        /// <summary>
        /// Writes the metadata properties for an entry which can occur both at the start or at the end.
        /// </summary>
        /// <param name="entryState">The entry state for which to write the metadata properties.</param>
        /// <remarks>
        /// This method will only write properties which were not written yet.
        /// </remarks>
        internal void WriteEntryMetadataProperties(IODataJsonLightWriterEntryState entryState)
        {
            Debug.Assert(entryState != null, "entryState != null");

            ODataEntry entry = entryState.Entry;

            // Write the "@odata.editLink": "edit-link-uri"
            Uri editLinkUriValue = entry.EditLink;

            if (editLinkUriValue != null && !entryState.EditLinkWritten)
            {
                this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataEditLink);
                this.JsonWriter.WriteValue(this.UriToString(
                                               entry.HasNonComputedEditLink
                    ? editLinkUriValue
                    : this.MetadataDocumentBaseUri.MakeRelativeUri(editLinkUriValue)));
                entryState.EditLinkWritten = true;
            }

            // Write the "@odata.readLink": "read-link-uri".
            // If readlink is identical to editlink, don't write readlink.
            Uri readLinkUriValue = entry.ReadLink;

            if (readLinkUriValue != null && readLinkUriValue != editLinkUriValue && !entryState.ReadLinkWritten)
            {
                this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataReadLink);
                this.JsonWriter.WriteValue(this.UriToString(
                                               entry.HasNonComputedReadLink
                    ? readLinkUriValue
                    : this.MetadataDocumentBaseUri.MakeRelativeUri(readLinkUriValue)));
                entryState.ReadLinkWritten = true;
            }

            // Write MLE metadata
            ODataStreamReferenceValue mediaResource = entry.MediaResource;

            if (mediaResource != null)
            {
                // Write the "@odata.mediaEditLink": "edit-link-uri"
                Uri mediaEditLinkUriValue = mediaResource.EditLink;
                if (mediaEditLinkUriValue != null && !entryState.MediaEditLinkWritten)
                {
                    this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataMediaEditLink);
                    this.JsonWriter.WriteValue(this.UriToString(
                                                   mediaResource.HasNonComputedEditLink
                        ? mediaEditLinkUriValue
                        : this.MetadataDocumentBaseUri.MakeRelativeUri(mediaEditLinkUriValue)));
                    entryState.MediaEditLinkWritten = true;
                }

                // Write the "@odata.mediaReadLink": "read-link-uri"
                // If mediaReadLink is identical to mediaEditLink, don't write readlink.
                Uri mediaReadLinkUriValue = mediaResource.ReadLink;
                if (mediaReadLinkUriValue != null && mediaReadLinkUriValue != mediaEditLinkUriValue && !entryState.MediaReadLinkWritten)
                {
                    this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataMediaReadLink);
                    this.JsonWriter.WriteValue(this.UriToString(
                                                   mediaResource.HasNonComputedReadLink
                        ? mediaReadLinkUriValue
                        : this.MetadataDocumentBaseUri.MakeRelativeUri(mediaReadLinkUriValue)));
                    entryState.MediaReadLinkWritten = true;
                }

                // Write the "@odata.mediaContentType": "content/type"
                string mediaContentType = mediaResource.ContentType;
                if (mediaContentType != null && !entryState.MediaContentTypeWritten)
                {
                    this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataMediaContentType);
                    this.JsonWriter.WriteValue(mediaContentType);
                    entryState.MediaContentTypeWritten = true;
                }

                // Write the "@odata.mediaEtag": "ETAG"
                string mediaETag = mediaResource.ETag;
                if (mediaETag != null && !entryState.MediaETagWritten)
                {
                    this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataMediaETag);
                    this.JsonWriter.WriteValue(mediaETag);
                    entryState.MediaETagWritten = true;
                }
            }

            // TODO: actions
            // TODO: functions
            // TODO: association links
        }
        /// <summary>
        /// Writes a stream property.
        /// </summary>
        /// <param name="propertyName">The name of the property to write.</param>
        /// <param name="streamReferenceValue">The stream reference value to be written</param>
        private void WriteStreamReferenceProperty(string propertyName, ODataStreamReferenceValue streamReferenceValue)
        {
            Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");
            Debug.Assert(streamReferenceValue != null, "streamReferenceValue != null");

            Uri mediaEditLink = streamReferenceValue.EditLink;
            if (mediaEditLink != null)
            {
                this.ODataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataMediaEditLink);
                this.JsonWriter.WriteValue(this.UriToString(mediaEditLink));
            }

            Uri mediaReadLink = streamReferenceValue.ReadLink;
            if (mediaReadLink != null)
            {
                this.ODataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataMediaReadLink);
                this.JsonWriter.WriteValue(this.UriToString(mediaReadLink));
            }

            string mediaContentType = streamReferenceValue.ContentType;
            if (mediaContentType != null)
            {
                this.ODataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataMediaContentType);
                this.JsonWriter.WriteValue(mediaContentType);
            }

            string mediaETag = streamReferenceValue.ETag;
            if (mediaETag != null)
            {
                this.ODataAnnotationWriter.WritePropertyAnnotationName(propertyName, ODataAnnotationNames.ODataMediaETag);
                this.JsonWriter.WriteValue(mediaETag);
            }
        }
示例#19
0
 /// <summary>
 /// Visits a stream reference value (named stream).
 /// </summary>
 /// <param name="streamReferenceValue">The stream reference value to visit.</param>
 protected abstract T VisitStreamReferenceValue(ODataStreamReferenceValue streamReferenceValue);
示例#20
0
        /// <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));
            }

            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));
            }

            if (objectModelItem is ODataUntypedValue)
            {
                object val = ODataObjectModelVisitor.ParseJsonToPrimitiveValue(
                    (objectModelItem as ODataUntypedValue).RawValue);
                return(this.VisitPrimitiveValue(val));
            }

            return(this.VisitUnsupportedValue(objectModelItem));
        }
示例#21
0
        private void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            bool allowStreamProperty,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            WriterValidationUtils.ValidatePropertyNotNull(property);

            string propertyName = property.Name;

            if (projectedProperties.ShouldSkipProperty(propertyName))
            {
                return;
            }

            WriterValidationUtils.ValidatePropertyName(propertyName);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
            IEdmProperty      edmProperty           = null;
            IEdmTypeReference propertyTypeReference = null;

            if (this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation)
            {
                edmProperty           = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType);
                propertyTypeReference = edmProperty == null ? null : edmProperty.Type;
            }

            ODataValue          value          = property.ODataValue;
            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null)
            {
                if (!allowStreamProperty)
                {
                    throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                }

                Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type.");
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse);
                this.WriteStreamReferenceProperty(propertyName, streamReferenceValue);
                return;
            }

            string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName;

            if (value is ODataNullValue || value == null)
            {
                WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model);

                if (isTopLevel)
                {
                    // Write the special null marker for top-level null properties.
                    this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull);
                    this.JsonWriter.WriteValue(true);
                }
                else
                {
                    this.JsonWriter.WriteName(wirePropertyName);
                    this.JsonLightValueSerializer.WriteNullValue();
                }

                return;
            }

            bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty);

            if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation)
            {
                ValidationUtils.ValidateOpenPropertyValue(propertyName, value);
            }

            ODataComplexValue complexValue = value as ODataComplexValue;

            if (complexValue != null)
            {
                if (!isTopLevel)
                {
                    this.JsonWriter.WriteName(wirePropertyName);
                }

                this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker());
                return;
            }

            IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType);
            ODataEnumValue    enumValue     = value as ODataEnumValue;

            if (enumValue != null)
            {
                string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(enumValue, propertyTypeReference, typeFromValue, isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);
                this.JsonWriter.WriteName(wirePropertyName);
                this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference);
                return;
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel);
                this.JsonWriter.WriteName(wirePropertyName);

                // passing false for 'isTopLevel' because the outer wrapping object has already been written.
                this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType);
            }
            else
            {
                Debug.Assert(primitiveValue != null, "primitiveValue != null");

                string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType);
                this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);

                this.JsonWriter.WriteName(wirePropertyName);
                this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference);
            }
        }
        /// <summary>
        /// Reads a stream property value from the property annotations.
        /// </summary>
        /// <param name="entryState">The state of the reader for entry to read.</param>
        /// <param name="streamPropertyName">The name of the stream property to read the value for.</param>
        /// <returns>The newly created stream reference value.</returns>
        private ODataStreamReferenceValue ReadStreamPropertyValue(IODataJsonLightReaderEntryState entryState, string streamPropertyName)
        {
            Debug.Assert(entryState != null, "entryState != null");
            Debug.Assert(!string.IsNullOrEmpty(streamPropertyName), "!string.IsNullOrEmpty(streamPropertyName)");

            // Fail on stream properties in requests as they cannot appear there.
            if (!this.ReadingResponse)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_StreamPropertyInRequest);
            }

            ODataStreamReferenceValue streamReferenceValue = new ODataStreamReferenceValue();

            Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(streamPropertyName);
            if (propertyAnnotations != null)
            {
                foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations)
                {
                    switch (propertyAnnotation.Key)
                    {
                        case ODataAnnotationNames.ODataMediaEditLink:
                            Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.mediaEditLink annotation should have been parsed as a non-null Uri.");
                            streamReferenceValue.EditLink = (Uri)propertyAnnotation.Value;
                            break;

                        case ODataAnnotationNames.ODataMediaReadLink:
                            Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.mediaReadLink annotation should have been parsed as a non-null Uri.");
                            streamReferenceValue.ReadLink = (Uri)propertyAnnotation.Value;
                            break;

                        case ODataAnnotationNames.ODataMediaETag:
                            Debug.Assert(propertyAnnotation.Value is string && propertyAnnotation.Value != null, "The odata.mediaEtag annotation should have been parsed as a non-null string.");
                            streamReferenceValue.ETag = (string)propertyAnnotation.Value;
                            break;

                        case ODataAnnotationNames.ODataMediaContentType:
                            Debug.Assert(propertyAnnotation.Value is string && propertyAnnotation.Value != null, "The odata.mediaContentType annotation should have been parsed as a non-null string.");
                            streamReferenceValue.ContentType = (string)propertyAnnotation.Value;
                            break;

                        default:
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedStreamPropertyAnnotation(streamPropertyName, propertyAnnotation.Key));
                    }
                }
            }

            ODataEntityMetadataBuilder builder = this.MetadataContext.GetEntityMetadataBuilderForReader(entryState, this.JsonLightInputContext.MessageReaderSettings.UseKeyAsSegment);

            // Note that we set the metadata builder even when streamProperty is null, which is the case when the stream property is undeclared.
            // For undeclared stream properties, we will apply conventional metadata evaluation just as declared stream properties.
            streamReferenceValue.SetMetadataBuilder(builder, streamPropertyName);

            return streamReferenceValue;
        }
        /// <summary>
        /// Writes the __metadata property and its content for an entry
        /// </summary>
        /// <param name="entry">The entry for which to write the metadata.</param>
        /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param>
        /// <param name="entryEntityType">The entity type of the entry to write.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
        internal void WriteEntryMetadata(
            ODataEntry entry,
            ProjectedPropertiesAnnotation projectedProperties,
            IEdmEntityType entryEntityType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(entry != null, "entry != null");

            // Write the "__metadata" for the entry
            this.JsonWriter.WriteName(JsonConstants.ODataMetadataName);
            this.JsonWriter.StartObjectScope();

            // Write the "id": "Entity Id"
            string id = entry.Id;

            if (id != null)
            {
                this.JsonWriter.WriteName(JsonConstants.ODataEntryIdName);
                this.JsonWriter.WriteValue(id);
            }

            // Write the "uri": "edit/read-link-uri"
            Uri uriValue = entry.EditLink ?? entry.ReadLink;

            if (uriValue != null)
            {
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataUriName);
                this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(uriValue));
            }

            // Write the "etag": "ETag value"
            // TODO: if this is a top-level entry also put the ETag into the headers.
            string etag = entry.ETag;

            if (etag != null)
            {
                this.WriteETag(JsonConstants.ODataMetadataETagName, etag);
            }

            // Write the "type": "typename"
            string typeName = entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            if (typeName != null)
            {
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                this.JsonWriter.WriteValue(typeName);
            }

            // Write MLE metadata
            ODataStreamReferenceValue mediaResource = entry.MediaResource;

            if (mediaResource != null)
            {
                WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true);
                this.WriteStreamReferenceValueContent(mediaResource);
            }

            // write "actions" metadata
            IEnumerable <ODataAction> actions = entry.Actions;

            if (actions != null)
            {
                this.WriteOperations(actions.Cast <ODataOperation>(), /*isAction*/ true);
            }

            // write "functions" metadata
            IEnumerable <ODataFunction> functions = entry.Functions;

            if (functions != null)
            {
                this.WriteOperations(functions.Cast <ODataOperation>(), /*isAction*/ false);
            }

            // Write properties metadata
            // For now only association links are supported here
            IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks;

            if (associationLinks != null)
            {
                bool firstAssociationLink = true;

                foreach (ODataAssociationLink associationLink in associationLinks)
                {
                    ValidationUtils.ValidateAssociationLinkNotNull(associationLink);
                    if (projectedProperties.ShouldSkipProperty(associationLink.Name))
                    {
                        continue;
                    }

                    if (firstAssociationLink)
                    {
                        // Write the "properties": {
                        this.JsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesName);
                        this.JsonWriter.StartObjectScope();

                        firstAssociationLink = false;
                    }

                    this.ValidateAssociationLink(associationLink, entryEntityType);
                    this.WriteAssociationLink(associationLink, duplicatePropertyNamesChecker);
                }

                if (!firstAssociationLink)
                {
                    // Close the "properties" object
                    this.JsonWriter.EndObjectScope();
                }
            }

            // Close the __metadata object scope
            this.JsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Writes the edit-media link for an entry.
        /// </summary>
        /// <param name="mediaResource">The media resource representing the MR of the entry to write.</param>
        internal void WriteEntryMediaEditLink(ODataStreamReferenceValue mediaResource)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(mediaResource != null, "mediaResource != null");

            Uri mediaEditLink = mediaResource.EditLink;
            Debug.Assert(mediaEditLink != null || mediaResource.ETag == null, "The default stream edit link and etag should have been validated by now.");
            if (mediaEditLink != null)
            {
                AtomStreamReferenceMetadata streamReferenceMetadata = mediaResource.GetAnnotation<AtomStreamReferenceMetadata>();
                AtomLinkMetadata mediaEditMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.EditLink;
                AtomLinkMetadata mergedLinkMetadata =
                    ODataAtomWriterMetadataUtils.MergeLinkMetadata(
                        mediaEditMetadata,
                        AtomConstants.AtomEditMediaRelationAttributeValue,
                        mediaEditLink,
                        null /* title */,
                        null /* mediaType */);

                this.atomEntryMetadataSerializer.WriteAtomLink(mergedLinkMetadata, mediaResource.ETag);
            }
        }
        /// <summary>
        /// Writes a name/value pair for a property.
        /// </summary>
        /// <param name="property">The property to write out.</param>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry or complex type containing the property (or null if not metadata is available).</param>
        /// <param name="allowStreamProperty">Should pass in true if we are writing a property of an ODataEntry instance, false otherwise.
        /// Named stream properties should only be defined on ODataEntry instances.</param>
        /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param>
        /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param>
        private void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool allowStreamProperty,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();

            WriterValidationUtils.ValidatePropertyNotNull(property);

            string propertyName = property.Name;
            object value        = property.Value;

            if (projectedProperties.ShouldSkipProperty(propertyName))
            {
                return;
            }

            WriterValidationUtils.ValidatePropertyName(propertyName);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
            IEdmProperty      edmProperty           = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds);
            IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type;

            // If the property is of Geography or Geometry type or the value is of Geography or Geometry type
            // make sure to check that the version is 3.0 or above.
            if ((propertyTypeReference != null && propertyTypeReference.IsSpatial()) ||
                (propertyTypeReference == null && value is System.Spatial.ISpatial))
            {
                ODataVersionChecker.CheckSpatialValue(this.Version);
            }

            this.JsonWriter.WriteName(propertyName);
            if (value == null)
            {
                WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model);
                this.JsonWriter.WriteValue(null);
            }
            else
            {
                bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null;
                if (isOpenPropertyType)
                {
                    ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds);
                }

                ODataComplexValue complexValue = value as ODataComplexValue;
                if (complexValue != null)
                {
                    this.WriteComplexValue(
                        complexValue,
                        propertyTypeReference,
                        isOpenPropertyType,
                        this.CreateDuplicatePropertyNamesChecker(),
                        /*collectionValidator*/ null);
                }
                else
                {
                    ODataCollectionValue collectionValue = value as ODataCollectionValue;
                    if (collectionValue != null)
                    {
                        ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName);
                        this.WriteCollectionValue(
                            collectionValue,
                            propertyTypeReference,
                            isOpenPropertyType);
                    }
                    else
                    {
                        ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;
                        if (streamReferenceValue != null)
                        {
                            if (!allowStreamProperty)
                            {
                                throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                            }

                            Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type.");
                            WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse);
                            WriterValidationUtils.ValidateStreamReferenceValue(streamReferenceValue, /*isDefaultStream*/ false);
                            this.WriteStreamReferenceValue(streamReferenceValue);
                        }
                        else
                        {
                            this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference);
                        }
                    }
                }
            }
        }