public void ReadInstanceAnnotationValueWillReadNullValueWithoutODataType()
 {
     var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.NullAnnotation\":null}");
     AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
     deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.NullAnnotation").Should().BeNull();
 }
        /// <summary>
        /// Read a service document. 
        /// This method reads the service document from the input and returns 
        /// an <see cref="ODataServiceDocument"/> that represents the read service document.
        /// </summary>
        /// <returns>A task which returns an <see cref="ODataServiceDocument"/> representing the read service document.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:        assumes that the JSON reader has not been used yet.
        /// Post-Condition: JsonNodeType.EndOfInput  
        /// </remarks>
        internal Task<ODataServiceDocument> ReadServiceDocumentAsync()
        {
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            this.JsonReader.AssertNotBuffering();

            // We use this to store annotations and check for duplicate annotation names, but we don't really store properties in it.
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

            // Position the reader on the first node
            return this.ReadPayloadStartAsync(
                ODataPayloadKind.ServiceDocument,
                duplicatePropertyNamesChecker,
                /*isReadingNestedPayload*/false,
                /*allowEmptyPayload*/false)

                .FollowOnSuccessWith(t =>
                    {
                        ODataServiceDocument serviceDocument = this.ReadServiceDocumentImplementation(duplicatePropertyNamesChecker);

                        // Read the end of the response.
                        this.ReadPayloadEnd(/*isReadingNestedPayload*/ false);

                        Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput");
                        this.JsonReader.AssertNotBuffering();

                        return serviceDocument;
                    });
        }
コード例 #3
0
        /// <summary>
        /// Read a service document.
        /// This method reads the service document from the input and returns
        /// an <see cref="ODataWorkspace"/> that represents the read service document.
        /// </summary>
        /// <returns>An <see cref="ODataWorkspace"/> representing the read service document.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:        assumes that the JSON reader has not been used yet.
        /// Post-Condition: JsonNodeType.EndOfInput
        /// </remarks>
        internal ODataWorkspace ReadServiceDocument()
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            this.JsonReader.AssertNotBuffering();

            // We use this to store annotations and check for duplicate annotation names, but we don't really store properties in it.
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

            // Position the reader on the first node
            this.ReadPayloadStart(
                ODataPayloadKind.ServiceDocument,
                duplicatePropertyNamesChecker,
                /*isReadingNestedPayload*/ false,
                /*allowEmptyPayload*/ false);

            ODataWorkspace resultWorkspace = this.ReadServiceDocumentImplementation(duplicatePropertyNamesChecker);

            // Read the end of the response.
            this.ReadPayloadEnd(/*isReadingNestedPayload*/ false);

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput");
            this.JsonReader.AssertNotBuffering();

            return(resultWorkspace);
        }
コード例 #4
0
 public void DuplicatePropertyCustomAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.AddCustomPropertyAnnotation("property", "custom.name");
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed("custom.name", "property"));
 }
コード例 #5
0
 public void OnlyCustomAnnotationsForPropertyAddedShouldReturnNull()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation");
     duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation2");
     duplicateChecker.GetODataPropertyAnnotations("property").Should().BeNull();
 }
コード例 #6
0
 public void DuplicatePropertyODataAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "name", null);
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(JsonLightConstants.ODataAnnotationNamespacePrefix + "name", "property"));
 }
コード例 #7
0
        /// <summary>
        /// Read a top-level error.
        /// </summary>
        /// <returns>An <see cref="ODataError"/> representing the read error.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None       - The reader must not have been used yet.
        /// Post-Condition: JsonNodeType.EndOfInput
        /// </remarks>
        internal ODataError ReadTopLevelError()
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            Debug.Assert(!this.JsonReader.DisableInStreamErrorDetection, "!JsonReader.DisableInStreamErrorDetection");
            this.JsonReader.AssertNotBuffering();

            // prevent the buffering JSON reader from detecting in-stream errors - we read the error ourselves
            // to throw proper exceptions
            this.JsonReader.DisableInStreamErrorDetection = true;

            // We use this to store annotations and check for duplicate annotation names, but we don't really store properties in it.
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

            try
            {
                // Position the reader on the first node
                this.ReadPayloadStart(
                    ODataPayloadKind.Error,
                    duplicatePropertyNamesChecker,
                    /*isReadingNestedPayload*/ false,
                    /*allowEmptyPayload*/ false);

                ODataError result = this.ReadTopLevelErrorImplementation();

                Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: JsonNodeType.EndOfInput");
                this.JsonReader.AssertNotBuffering();

                return(result);
            }
            finally
            {
                this.JsonReader.DisableInStreamErrorDetection = false;
            }
        }
コード例 #8
0
        /// <summary>
        /// Read a set of top-level entity reference links.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use for the top-level scope.</param>
        /// <returns>An <see cref="ODataEntityReferenceLinks"/> representing the read links.</returns>
        private ODataEntityReferenceLinks ReadEntityReferenceLinksImplementation(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");

            ODataEntityReferenceLinks entityReferenceLinks = new ODataEntityReferenceLinks();

            this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/ true);

            // Read the start of the content array of the links
            this.JsonReader.ReadStartArray();

            List <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>();
            DuplicatePropertyNamesChecker   linkDuplicatePropertyNamesChecker = this.JsonLightInputContext.CreateDuplicatePropertyNamesChecker();

            while (this.JsonReader.NodeType != JsonNodeType.EndArray)
            {
                // read another link
                ODataEntityReferenceLink entityReferenceLink = this.ReadSingleEntityReferenceLink(linkDuplicatePropertyNamesChecker, /*topLevel*/ false);
                links.Add(entityReferenceLink);
                linkDuplicatePropertyNamesChecker.Clear();
            }

            this.JsonReader.ReadEndArray();

            this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/ false);

            this.JsonReader.ReadEndObject();

            entityReferenceLinks.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(links);
            return(entityReferenceLinks);
        }
コード例 #9
0
        /// <summary>
        /// Implementation of the collection reader logic when in state 'Start'.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the top-level scope.</param>
        /// <returns>true if more items can be read from the reader; otherwise false.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet when not reading a nested payload.
        /// Post-Condition: The reader is positioned on the first node of the first item or the EndArray node of an empty item array
        /// </remarks>
        private bool ReadAtStartImplementationSynchronously(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");

            IEdmTypeReference actualItemTypeReference;

            this.ExpectedItemTypeReference = ReaderValidationUtils.ValidateCollectionContextUriAndGetPayloadItemTypeReference(
                this.jsonLightCollectionDeserializer.ContextUriParseResult,
                this.ExpectedItemTypeReference);

            // read the start of the collection until we find the content array for top-level collections
            ODataCollectionStart collectionStart = this.jsonLightCollectionDeserializer.ReadCollectionStart(
                duplicatePropertyNamesChecker,
                this.IsReadingNestedPayload,
                this.ExpectedItemTypeReference,
                out actualItemTypeReference);

            if (actualItemTypeReference != null)
            {
                this.ExpectedItemTypeReference = actualItemTypeReference;
            }

            this.jsonLightCollectionDeserializer.JsonReader.ReadStartArray();

            this.EnterScope(ODataCollectionReaderState.CollectionStart, collectionStart);

            return(true);
        }
コード例 #10
0
        /// <summary>
        /// Read a set of top-level entity reference links.
        /// </summary>
        /// <returns>A task which returns an <see cref="ODataEntityReferenceLinks"/> representing the read links.</returns>
        internal Task <ODataEntityReferenceLinks> ReadEntityReferenceLinksAsync()
        {
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None, the reader must not have been used yet.");
            this.JsonReader.AssertNotBuffering();

            // We use this to store annotations and check for duplicate annotation names, but we don't really store properties in it.
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

            return(this.ReadPayloadStartAsync(
                       ODataPayloadKind.EntityReferenceLinks,
                       duplicatePropertyNamesChecker,
                       /*isReadingNestedPayload*/ false,
                       /*allowEmptyPayload*/ false)

                   .FollowOnSuccessWith(t =>
            {
                ODataEntityReferenceLinks entityReferenceLinks = this.ReadEntityReferenceLinksImplementation(duplicatePropertyNamesChecker);

                this.ReadPayloadEnd(/*isReadingNestedPayload*/ false);

                Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndOfInput, "Post-Condition: expected JsonNodeType.EndOfInput");
                this.JsonReader.AssertNotBuffering();

                return entityReferenceLinks;
            }));
        }
コード例 #11
0
        private ODataCollectionValue ReadCollectionValue(IEdmCollectionTypeReference collectionTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            this.IncreaseRecursionDepth();
            ODataCollectionValue value2 = new ODataCollectionValue {
                TypeName = (collectionTypeReference == null) ? payloadTypeName : collectionTypeReference.ODataFullName()
            };

            if (serializationTypeNameAnnotation != null)
            {
                value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation);
            }
            base.XmlReader.MoveToElement();
            List <object> sourceEnumerable = new List <object>();

            if (!base.XmlReader.IsEmptyElement)
            {
                base.XmlReader.ReadStartElement();
                IEdmTypeReference                      expectedTypeReference         = (collectionTypeReference == null) ? null : collectionTypeReference.ElementType();
                DuplicatePropertyNamesChecker          duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                CollectionWithoutExpectedTypeValidator collectionValidator           = null;
                if (collectionTypeReference == null)
                {
                    string itemTypeNameFromCollection = (payloadTypeName == null) ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName);
                    collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection);
                }
                do
                {
                    switch (base.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace))
                        {
                            if (!base.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
                            {
                                throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(base.XmlReader.LocalName, base.XmlReader.ODataNamespace));
                            }
                            object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true, false);
                            base.XmlReader.Read();
                            ValidationUtils.ValidateCollectionItem(item, false);
                            sourceEnumerable.Add(item);
                        }
                        else
                        {
                            base.XmlReader.Skip();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        break;

                    default:
                        base.XmlReader.Skip();
                        break;
                    }
                }while (base.XmlReader.NodeType != XmlNodeType.EndElement);
            }
            value2.Items = new ReadOnlyEnumerable(sourceEnumerable);
            this.DecreaseRecursionDepth();
            return(value2);
        }
コード例 #12
0
 public void DuplicateInstanceCustomAnnotationShouldFail()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => duplicateChecker.MarkPropertyAsProcessed("custom.name");
     action.ShouldNotThrow();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed("custom.name"));
 }
コード例 #13
0
        /// <summary>
        /// Writes property names and value pairs.
        /// </summary>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param>
        /// <param name="properties">The enumeration of properties to write out.</param>
        /// <param name="isComplexValue">
        /// Whether the properties are being written for complex value. Also used for detecting whether stream properties
        /// are allowed as 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>
        internal void WriteProperties(
            IEdmStructuredType owningType,
            IEnumerable <ODataProperty> properties,
            bool isComplexValue,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();

            if (properties == null)
            {
                return;
            }

            foreach (ODataProperty property in properties)
            {
                this.WriteProperty(
                    property,
                    owningType,
                    false /* isTopLevel */,
                    !isComplexValue,
                    duplicatePropertyNamesChecker,
                    projectedProperties);
            }
        }
コード例 #14
0
        /// <summary>
        /// Parses JSON object property starting with the current position of the JSON reader.
        /// </summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use, it will also store the property annotations found.</param>
        /// <param name="readPropertyAnnotationValue">Function called to read property annotation value.</param>
        /// <param name="handleProperty">Function callback to handle to resule of parse property.</param>
        internal void ProcessProperty(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            Func <string, object> readPropertyAnnotationValue,
            Action <PropertyParsingResult, string> handleProperty)
        {
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(readPropertyAnnotationValue != null, "readPropertyAnnotationValue != null");
            Debug.Assert(handleProperty != null, "handleProperty != null");
            this.AssertJsonCondition(JsonNodeType.Property);

            string propertyName;
            PropertyParsingResult propertyParsingResult = this.ParseProperty(duplicatePropertyNamesChecker, readPropertyAnnotationValue, out propertyName);

            while (propertyParsingResult == PropertyParsingResult.CustomInstanceAnnotation && this.ShouldSkipCustomInstanceAnnotation(propertyName))
            {
                // Make sure there's no duplicated instance annotation name even though we are skipping over it.
                duplicatePropertyNamesChecker.MarkPropertyAsProcessed(propertyName);

                // Skip over the instance annotation value and don't report it to the OM.
                this.JsonReader.SkipValue();

                propertyParsingResult = this.ParseProperty(duplicatePropertyNamesChecker, readPropertyAnnotationValue, out propertyName);
            }

            handleProperty(propertyParsingResult, propertyName);
            if (propertyParsingResult != PropertyParsingResult.EndOfObject)
            {
                duplicatePropertyNamesChecker.MarkPropertyAsProcessed(propertyName);
            }
        }
コード例 #15
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="atomInputContext">The ATOM input context to read from.</param>
        internal ODataAtomCollectionDeserializer(ODataAtomInputContext atomInputContext)
            : base(atomInputContext)
        {
            DebugUtils.CheckNoExternalCallers();

            this.duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
        }
コード例 #16
0
        /// <summary>
        /// Write the given collection of properties.
        /// </summary>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param>
        /// <param name="cachedProperties">Collection of cached properties for the entry.</param>
        /// <param name="isWritingCollection">true if we are writing a top level collection instead of an entry.</param>
        /// <param name="beforePropertiesAction">Action which is called before the properties are written, if there are any property.</param>
        /// <param name="afterPropertiesAction">Action which is called after the properties are written, if there are any property.</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>
        /// <returns>true if anything was written, false otherwise.</returns>
        internal bool WriteProperties(
            IEdmStructuredType owningType,
            IEnumerable <ODataProperty> cachedProperties,
            bool isWritingCollection,
            Action beforePropertiesAction,
            Action afterPropertiesAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            if (cachedProperties == null)
            {
                return(false);
            }

            bool propertyWritten = false;

            foreach (ODataProperty property in cachedProperties)
            {
                propertyWritten |= this.WriteProperty(
                    property,
                    owningType,
                    /*isTopLevel*/ false,
                    isWritingCollection,
                    propertyWritten ? null : beforePropertiesAction,
                    duplicatePropertyNamesChecker,
                    projectedProperties);
            }

            if (afterPropertiesAction != null && propertyWritten)
            {
                afterPropertiesAction();
            }

            return(propertyWritten);
        }
コード例 #17
0
        /// <summary>
        /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal.
        /// </summary>
        /// <param name="associationLink">The association link for which to write the metadata.</param>
        /// <param name="owningType">The <see cref="IEdmEntityType"/> instance the association link is defined on.</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>
        internal void WriteAssociationLink(
            ODataAssociationLink associationLink,
            IEdmEntityType owningType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();

            ValidationUtils.ValidateAssociationLinkNotNull(associationLink);
            string associationLinkName = associationLink.Name;

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

            this.ValidateAssociationLink(associationLink, owningType);
            duplicatePropertyNamesChecker.CheckForDuplicateAssociationLinkNames(associationLink);

            AtomLinkMetadata linkMetadata       = associationLink.GetAnnotation <AtomLinkMetadata>();
            string           linkRelation       = AtomUtils.ComputeODataAssociationLinkRelation(associationLink);
            AtomLinkMetadata mergedLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, associationLink.Url, associationLinkName, MimeConstants.MimeApplicationXml);

            this.atomEntryMetadataSerializer.WriteAtomLink(mergedLinkMetadata, null /* etag*/);
        }
コード例 #18
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="jsonInputContext">The JSON input context to read from.</param>
        internal ODataVerboseJsonCollectionDeserializer(ODataVerboseJsonInputContext jsonInputContext)
            : base(jsonInputContext)
        {
            DebugUtils.CheckNoExternalCallers();

            this.duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
        }
コード例 #19
0
        /// <summary>
        /// Read the start of the top-level data wrapper in JSON responses.
        /// </summary>
        /// <param name="payloadKind">The kind of payload we are reading; this guides the parsing of the context URI.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param>
        /// <param name="isReadingNestedPayload">true if we are deserializing a nested payload, e.g. an entry, a feed or a collection within a parameters payload.</param>
        /// <param name="allowEmptyPayload">true if we allow a comletely empty payload; otherwise false.</param>
        /// <returns>The parsed context URI.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet when not reading a nested payload.
        /// Post-Condition: The reader is positioned on the first property of the payload after having read (or skipped) the context URI property.
        ///                 Or the reader is positioned on an end-object node if there are no properties (other than the context URI which is required in responses and optional in requests).
        /// </remarks>
        internal Task ReadPayloadStartAsync(
            ODataPayloadKind payloadKind,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            bool isReadingNestedPayload,
            bool allowEmptyPayload)
        {
            this.JsonReader.AssertNotBuffering();
            Debug.Assert(isReadingNestedPayload || this.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: JSON reader must not have been used yet when not reading a nested payload.");

            return(TaskUtils.GetTaskForSynchronousOperation(() =>
            {
                string contextUriAnnotationValue = this.ReadPayloadStartImplementation(
                    payloadKind,
                    duplicatePropertyNamesChecker,
                    isReadingNestedPayload,
                    allowEmptyPayload);

                // The context URI is only recognized in non-error response top-level payloads.
                // If the payload is nested (for example when we read URL literals) we don't recognize the context URI.
                // Top-level error payloads don't need and use the context URI.
                if (!isReadingNestedPayload && payloadKind != ODataPayloadKind.Error && contextUriAnnotationValue != null)
                {
                    this.contextUriParseResult = ODataJsonLightContextUriParser.Parse(
                        this.Model,
                        contextUriAnnotationValue,
                        payloadKind,
                        this.MessageReaderSettings.ReaderBehavior,
                        this.JsonLightInputContext.ReadingResponse);
                }

#if DEBUG
                this.contextUriParseResultReady = true;
#endif
            }));
        }
コード例 #20
0
        public void DuplicatePropertyODataAnnotationShouldFail()
        {
            DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
            Action action = () => duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "name", null);

            action.ShouldNotThrow();
            action.ShouldThrow <ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(JsonLightConstants.ODataAnnotationNamespacePrefix + "name", "property"));
        }
コード例 #21
0
        public void DuplicatePropertyCustomAnnotationShouldFail()
        {
            DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
            Action action = () => duplicateChecker.AddCustomPropertyAnnotation("property", "custom.name");

            action.ShouldNotThrow();
            action.ShouldThrow <ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed("custom.name", "property"));
        }
コード例 #22
0
        public void OnlyCustomAnnotationsForPropertyAddedShouldReturnNull()
        {
            DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);

            duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation");
            duplicateChecker.AddCustomPropertyAnnotation("property", "custom.annotation2");
            duplicateChecker.GetODataPropertyAnnotations("property").Should().BeNull();
        }
コード例 #23
0
        public void DuplicateInstanceCustomAnnotationShouldFail()
        {
            DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
            Action action = () => duplicateChecker.MarkPropertyAsProcessed("custom.name");

            action.ShouldNotThrow();
            action.ShouldThrow <ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed("custom.name"));
        }
コード例 #24
0
        internal void WriteCollectionValue(ODataCollectionValue collectionValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType)
        {
            this.IncreaseRecursionDepth();
            base.JsonWriter.StartObjectScope();
            string typeName = collectionValue.TypeName;
            IEdmCollectionTypeReference type  = (IEdmCollectionTypeReference)WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType);
            string itemTypeNameFromCollection = null;

            if (typeName != null)
            {
                itemTypeNameFromCollection = ValidationUtils.ValidateCollectionTypeName(typeName);
            }
            SerializationTypeNameAnnotation annotation = collectionValue.GetAnnotation <SerializationTypeNameAnnotation>();

            if (annotation != null)
            {
                typeName = annotation.TypeName;
            }
            if (typeName != null)
            {
                base.JsonWriter.WriteName("__metadata");
                base.JsonWriter.StartObjectScope();
                base.JsonWriter.WriteName("type");
                base.JsonWriter.WriteValue(typeName);
                base.JsonWriter.EndObjectScope();
            }
            base.JsonWriter.WriteDataArrayName();
            base.JsonWriter.StartArrayScope();
            IEnumerable items = collectionValue.Items;

            if (items != null)
            {
                IEdmTypeReference propertyTypeReference = (type == null) ? null : type.ElementType();
                CollectionWithoutExpectedTypeValidator collectionValidator           = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection);
                DuplicatePropertyNamesChecker          duplicatePropertyNamesChecker = null;
                foreach (object obj2 in items)
                {
                    ValidationUtils.ValidateCollectionItem(obj2, false);
                    ODataComplexValue complexValue = obj2 as ODataComplexValue;
                    if (complexValue != null)
                    {
                        if (duplicatePropertyNamesChecker == null)
                        {
                            duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                        }
                        this.WriteComplexValue(complexValue, propertyTypeReference, false, duplicatePropertyNamesChecker, collectionValidator);
                        duplicatePropertyNamesChecker.Clear();
                    }
                    else
                    {
                        this.WritePrimitiveValue(obj2, collectionValidator, propertyTypeReference);
                    }
                }
            }
            base.JsonWriter.EndArrayScope();
            base.JsonWriter.EndObjectScope();
            this.DecreaseRecursionDepth();
        }
コード例 #25
0
 private void WriteAssociationLink(ODataAssociationLink associationLink, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink);
     base.JsonWriter.WriteName(associationLink.Name);
     base.JsonWriter.StartObjectScope();
     base.JsonWriter.WriteName("associationuri");
     base.JsonWriter.WriteValue(base.UriToAbsoluteUriString(associationLink.Url));
     base.JsonWriter.EndObjectScope();
 }
コード例 #26
0
        /// <summary>
        /// Writes a stream property to the ATOM payload
        /// </summary>
        /// <param name="streamProperty">The stream property to create the payload for.</param>
        /// <param name="owningType">The <see cref="IEdmEntityType"/> instance for which the stream property defined on.</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>
        internal void WriteStreamProperty(
            ODataProperty streamProperty,
            IEdmEntityType owningType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(streamProperty != null, "Stream property must not be null.");
            Debug.Assert(streamProperty.Value != null, "The media resource of the stream property must not be null.");

            WriterValidationUtils.ValidatePropertyNotNull(streamProperty);
            string propertyName = streamProperty.Name;

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

            WriterValidationUtils.ValidatePropertyName(propertyName);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty);
            IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds);

            WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, this.Version, this.WritingResponse);
            ODataStreamReferenceValue streamReferenceValue = (ODataStreamReferenceValue)streamProperty.Value;

            WriterValidationUtils.ValidateStreamReferenceValue(streamReferenceValue, false /*isDefaultStream*/);
            if (owningType != null && owningType.IsOpen && edmProperty == null)
            {
                ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamReferenceValue, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds);
            }

            AtomStreamReferenceMetadata streamReferenceMetadata = streamReferenceValue.GetAnnotation <AtomStreamReferenceMetadata>();
            string contentType = streamReferenceValue.ContentType;
            string linkTitle   = streamProperty.Name;

            Uri readLink = streamReferenceValue.ReadLink;

            if (readLink != null)
            {
                string readLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false);

                AtomLinkMetadata readLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.SelfLink;
                AtomLinkMetadata mergedMetadata   = ODataAtomWriterMetadataUtils.MergeLinkMetadata(readLinkMetadata, readLinkRelation, readLink, linkTitle, contentType);
                this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, null /* etag */);
            }

            Uri editLink = streamReferenceValue.EditLink;

            if (editLink != null)
            {
                string editLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true);

                AtomLinkMetadata editLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.EditLink;
                AtomLinkMetadata mergedMetadata   = ODataAtomWriterMetadataUtils.MergeLinkMetadata(editLinkMetadata, editLinkRelation, editLink, linkTitle, contentType);
                this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, streamReferenceValue.ETag);
            }
        }
        public void ReadInstanceAnnotationValueWillReadNonJsonNativePrimitiveTypesWithoutODataTypeAsStringValue()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@Custom.GuidAnnotation\":\"00000000-0000-0000-0000-000000000000\"}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "Custom.GuidAnnotation").Should().Be("00000000-0000-0000-0000-000000000000");
        }
        public void ReadInstanceAnnotationValueWillReadNullValueWithoutODataType()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@odata.NullAnnotation\":null}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "odata.NullAnnotation").Should().BeNull();
        }
        public void ReadInstanceAnnotationValueWillReadAsCorrectTypePrimitiveTypesWithODataTypeAnnotation()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@Custom.GuidAnnotation\":\"00000000-0000-0000-0000-000000000000\"}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            duplicatePropertyNamesChecker.AddODataPropertyAnnotation("Custom.GuidAnnotation", "odata.type", "Edm.Guid");
            deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "Custom.GuidAnnotation").Should().Be(Guid.Empty);
        }
        public void ReadInstanceAnnotationValueWillFailIfODataTypeAnnotationIsMissingForCollectionValue()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@OData.CollectionAnnotation\":[]}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var    duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
            Action action = () => deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "OData.CollectionAnnotation");

            action.ShouldThrow <ODataException>().WithMessage(ErrorStrings.ReaderValidationUtils_ValueWithoutType);
        }
        public void ReadEntryInstanceAnnotationShouldReadCustomInstanceAnnotationValue()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.Int32Annotation\":123}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var    duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
            object value = deserializer.ReadEntryInstanceAnnotation("custom.Int32Annotation", false /*anyPropertyFound*/, true /*typeAnnotationFound*/, duplicatePropertyNamesChecker);

            Assert.AreEqual(123, value);
        }
コード例 #32
0
        /// <summary>
        /// Reads the end of a collection; this includes collection-level instance annotations.
        /// </summary>
        /// <param name="isReadingNestedPayload">true if we are reading a nested collection inside a paramter payload; otherwise false.</param>
        /// <remarks>
        /// Pre-Condition:  EndArray node:      End of the collection content array
        /// Post-Condition: EndOfInput:         All of the collection payload has been consumed.
        /// </remarks>
        internal void ReadCollectionEnd(bool isReadingNestedPayload)
        {
            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndArray, "Pre-condition: JsonNodeType.EndArray");
            this.JsonReader.AssertNotBuffering();

            this.JsonReader.ReadEndArray();

            if (!isReadingNestedPayload)
            {
                // Create a new duplicate property names checker object here; we don't have to use the one from reading the
                // collection start since we don't allow any annotations/properties after the collection property.
                DuplicatePropertyNamesChecker collectionEndDuplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();

                // Fail on anything after the collection that is not a custom instance annotation
                while (this.JsonReader.NodeType == JsonNodeType.Property)
                {
                    this.ProcessProperty(
                        collectionEndDuplicatePropertyNamesChecker,
                        this.ReadTypePropertyAnnotationValue,
                        (propertyParsingResult, propertyName) =>
                    {
                        // This method will allow and skip over any custom annotations, but will not report them as enum values, so any result we get other than EndOfObject indicates a malformed payload.
                        switch (propertyParsingResult)
                        {
                        case PropertyParsingResult.CustomInstanceAnnotation:
                            this.JsonReader.SkipValue();
                            break;

                        case PropertyParsingResult.ODataInstanceAnnotation:
                            if (!IsValidODataAnnotationOfCollection(propertyName))
                            {
                                throw new ODataException(ODataErrorStrings.ODataJsonLightCollectionDeserializer_CannotReadCollectionEnd(propertyName));
                            }

                            this.JsonReader.SkipValue();
                            break;

                        case PropertyParsingResult.PropertyWithoutValue:                // fall through
                        case PropertyParsingResult.PropertyWithValue:                   // fall through
                        case PropertyParsingResult.MetadataReferenceProperty:
                            throw new ODataException(ODataErrorStrings.ODataJsonLightCollectionDeserializer_CannotReadCollectionEnd(propertyName));

                        case PropertyParsingResult.EndOfObject:
                            break;

                        default:
                            throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightCollectionDeserializer_ReadCollectionEnd));
                        }
                    });
                }

                // read the end-object node of the value containing the 'value' property
                this.JsonReader.ReadEndObject();
            }
        }
        public void ReadTopLevelFeedAnnotationsForFeedEndAndBufferingShouldSkipAllValues()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.before\":123,\"value\":[],\"@custom.after\":456}");

            AdvanceReaderToFirstProperty(deserializer.JsonReader);
            var feed = new ODataFeed();
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            deserializer.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, false /*forFeedStart*/, true /*readAllFeedProperties*/);
            feed.InstanceAnnotations.Should().BeEmpty();
        }
        public void ReadTopLevelFeedAnnotationsForFeedEndAndNonBufferingShouldSkipInstanceAnnotationsBasedOnReaderSettings()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@custom.after\":456}", shouldReadAndValidateCustomInstanceAnnotations: false);

            AdvanceReaderToFirstProperty(deserializer.JsonReader);
            var feed = new ODataFeed();
            var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);

            deserializer.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, false /*forFeedStart*/, false /*readAllFeedProperties*/);
            Assert.AreEqual(0, feed.InstanceAnnotations.Count);
        }
コード例 #35
0
 public void AnnotationsForPropertyShouldBeStored()
 {
     DuplicatePropertyNamesChecker duplicateChecker = new DuplicatePropertyNamesChecker(false, true);
     duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "one", 1);
     duplicateChecker.AddODataPropertyAnnotation("property", JsonLightConstants.ODataAnnotationNamespacePrefix + "two", "Two");
     duplicateChecker.GetODataPropertyAnnotations("property").Should().Equal(new Dictionary<string, object>()
     {
         { JsonLightConstants.ODataAnnotationNamespacePrefix + "one", 1 },
         { JsonLightConstants.ODataAnnotationNamespacePrefix + "two", "Two" }
     });
 }
コード例 #36
0
        public void ReadInstanceAnnotationValueWhenODataTypeAnnotationIsMissingForCollectionValue()
        {
            var deserializer = this.CreateJsonLightEntryAndFeedDeserializer("{\"@OData.CollectionAnnotation\":[]}");

            AdvanceReaderToFirstPropertyValue(deserializer.JsonReader);
            var    duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false /*allowDuplicateProperties*/, true /*isResponse*/);
            object tmp = deserializer.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, "OData.CollectionAnnotation");

            tmp.As <ODataCollectionValue>().Items.Cast <string>().Count().Should().Be(0);
            tmp.As <ODataCollectionValue>().TypeName.ShouldBeEquivalentTo(null);
        }
コード例 #37
0
        /// <summary>
        /// Implementation of the reader logic when in state 'Start'.
        /// </summary>
        /// <returns>true if more items can be read from the reader; otherwise false.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet.
        /// Post-Condition: When the new state is Value, the reader is positioned at the closing '}' or at the name of the next parameter.
        ///                 When the new state is Entry, the reader is positioned at the starting '{' of the entry payload.
        ///                 When the new state is Feed or Collection, the reader is positioned at the starting '[' of the feed or collection payload.
        /// </remarks>
        protected override bool ReadAtStartImplementation()
        {
            Debug.Assert(this.State == ODataParameterReaderState.Start, "this.State == ODataParameterReaderState.Start");
            Debug.Assert(this.jsonLightParameterDeserializer.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None");

            // We use this to store annotations and check for duplicate annotation names, but we don't really store properties in it.
            this.duplicatePropertyNamesChecker = this.jsonLightInputContext.CreateDuplicatePropertyNamesChecker();

            // The parameter payload looks like "{ param1 : value1, ..., paramN : valueN }", where each value can be primitive, complex, collection, entity, feed or collection.
            // Position the reader on the first node
            this.jsonLightParameterDeserializer.ReadPayloadStart(
                ODataPayloadKind.Parameter,
                this.duplicatePropertyNamesChecker,
                /*isReadingNestedPayload*/false,
                /*allowEmptyPayload*/true);

            return this.ReadAtStartImplementationSynchronously();
        }
コード例 #38
0
        /// <summary>
        /// Reads the feed instance annotations for a top-level feed.
        /// </summary>
        /// <param name="feed">The <see cref="ODataFeed"/> to read the instance annotations for.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the top-level scope.</param>
        /// <param name="forFeedStart">true when parsing the instance annotations before the feed property; 
        /// false when parsing the instance annotations after the feed property.</param>
        /// <param name="readAllFeedProperties">true if we should scan ahead for the annotations and ignore the actual data properties (used with
        /// the reordering reader); otherwise false.</param>
        internal void ReadTopLevelFeedAnnotations(ODataFeedBase feed, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool forFeedStart, bool readAllFeedProperties)
        {
            Debug.Assert(feed != null, "feed != null");
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            this.JsonReader.AssertNotBuffering();

            bool buffering = false;
            try
            {
                while (this.JsonReader.NodeType == JsonNodeType.Property)
                {
                    bool foundValueProperty = false;

                    if (!forFeedStart && readAllFeedProperties)
                    {
                        // If this is not called for reading FeedStart and we already scanned ahead and processed all feed properties, we already checked for duplicate property names.
                        // Use an empty duplicate property name checker since this.ParseProperty() read through the same property annotation of instance annotations again. 
                        duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(/*allowDuplicateProperties*/ true, this.JsonLightInputContext.ReadingResponse, !this.JsonLightInputContext.MessageReaderSettings.EnableFullValidation);
                    }

                    this.ProcessProperty(
                        duplicatePropertyNamesChecker,
                        this.ReadTypePropertyAnnotationValue,
                        (propertyParseResult, propertyName) =>
                        {
                            switch (propertyParseResult)
                            {
                                case PropertyParsingResult.ODataInstanceAnnotation:
                                case PropertyParsingResult.CustomInstanceAnnotation:
                                    // When we are reading the start of a feed (in scan-ahead mode or not) or when
                                    // we read the end of a feed and not in scan-ahead mode, read the value;
                                    // otherwise skip it.
                                    if (forFeedStart || !readAllFeedProperties)
                                    {
                                        this.ReadAndApplyFeedInstanceAnnotationValue(propertyName, feed, duplicatePropertyNamesChecker);
                                    }
                                    else
                                    {
                                        this.JsonReader.SkipValue();
                                    }

                                    break;

                                case PropertyParsingResult.PropertyWithValue:
                                    if (string.CompareOrdinal(JsonLightConstants.ODataValuePropertyName, propertyName) == 0)
                                    {
                                        // We found the feed property and are done parsing property annotations;
                                        // When we are in the mode where we scan ahead and read all feed properties
                                        // (for the reordering scenario), we have to start buffering and continue 
                                        // reading. Otherwise we found the feed's data property and are done.
                                        if (readAllFeedProperties)
                                        {
                                            this.JsonReader.StartBuffering();
                                            buffering = true;

                                            this.JsonReader.SkipValue();
                                        }
                                        else
                                        {
                                            foundValueProperty = true;
                                        }
                                    }
                                    else
                                    {
                                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_InvalidPropertyInTopLevelFeed(propertyName, JsonLightConstants.ODataValuePropertyName));
                                    }

                                    break;
                                case PropertyParsingResult.PropertyWithoutValue:
                                    // If we find a property without a value it means that we did not find the feed property (yet)
                                    // but an invalid property annotation
                                    throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_InvalidPropertyAnnotationInTopLevelFeed(propertyName));

                                case PropertyParsingResult.EndOfObject:
                                    break;

                                case PropertyParsingResult.MetadataReferenceProperty:
                                    if (!(feed is ODataFeed))
                                    {
                                        throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName));
                                    }

                                    this.ReadMetadataReferencePropertyValue((ODataFeed)feed, propertyName);
                                    break;

                                default:
                                    throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataJsonLightEntryAndFeedDeserializer_ReadTopLevelFeedAnnotations));
                            }
                        });

                    if (foundValueProperty)
                    {
                        return;
                    }
                }
            }
            finally
            {
                if (buffering)
                {
                    Debug.Assert(readAllFeedProperties, "Expect the reader to be in buffering mode only when scanning to the end.");
                    this.JsonReader.StopBuffering();
                }
            }

            if (forFeedStart && !readAllFeedProperties)
            {
                // We did not find any properties or only instance annotations.
                throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_ExpectedFeedPropertyNotFound(JsonLightConstants.ODataValuePropertyName));
            }
        }
コード例 #39
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="atomInputContext">The ATOM input context to read from.</param>
 internal ODataAtomCollectionDeserializer(ODataAtomInputContext atomInputContext)
     : base(atomInputContext)
 {
     this.duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
 }
コード例 #40
0
 public void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isTopLevel, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     this.WriteComplexVerifier.Should().NotBeNull("WriteComplexValue was called.");
     this.WriteComplexVerifier(complexValue, metadataTypeReference, isTopLevel, isOpenPropertyType, duplicatePropertyNamesChecker);
 }
コード例 #41
0
        private void RunPropertyParsingTest(
            string jsonInput,
            ODataJsonLightDeserializer.PropertyParsingResult expectedPropertyParsingResult,
            string expectedName,
            Action<JsonReader, DuplicatePropertyNamesChecker> additionalVerification = null,
            Func<JsonReader, string, object> readPropertyAnnotationValue = null,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null)
        {
            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false, true);
            }
            if (readPropertyAnnotationValue == null)
            {
                readPropertyAnnotationValue = (jsonReader, annotationName) => jsonReader.ReadPrimitiveValue();
            }

            using (ODataJsonLightInputContext inputContext = this.CreateJsonLightInputContext(jsonInput))
            {
                ODataJsonLightDeserializer deserializer = new ODataJsonLightPropertyAndValueDeserializer(inputContext);
                AdvanceReaderToFirstProperty(deserializer.JsonReader);

                deserializer.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    (propertyName) => readPropertyAnnotationValue(deserializer.JsonReader, propertyName),
                    (propertyParsingResult, propertyName) =>
                    {
                        propertyParsingResult.Should().Be(expectedPropertyParsingResult, "parsing JSON object '{0}'", jsonInput);
                        propertyName.Should().Be(expectedName, "reported name is wrong for JSON object '{0}'", jsonInput);
                        if (additionalVerification != null)
                        {
                            additionalVerification(deserializer.JsonReader, duplicatePropertyNamesChecker);
                        }
                    });
            }
        }
コード例 #42
0
        /// <summary>
        /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal.
        /// </summary>
        /// <param name="associationLink">The association link for which to write the metadata.</param>
        /// <param name="owningType">The <see cref="IEdmEntityType"/> instance the association link is defined on.</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>
        internal void WriteAssociationLink(
            ODataAssociationLink associationLink,
            IEdmEntityType owningType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();

            ValidationUtils.ValidateAssociationLinkNotNull(associationLink);
            if (projectedProperties.ShouldSkipProperty(associationLink.Name))
            {
                return;
            }

            this.ValidateAssociationLink(associationLink, owningType);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink);

            AtomLinkMetadata linkMetadata = associationLink.GetAnnotation<AtomLinkMetadata>();
            string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink);
            AtomLinkMetadata mergedLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, associationLink.Url, associationLink.Name, MimeConstants.MimeApplicationXml);
            this.atomEntryMetadataSerializer.WriteAtomLink(mergedLinkMetadata, null /* etag*/);
        }
コード例 #43
0
        internal bool WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference metadataTypeReference,
            bool isOpenPropertyType,
            bool isWritingCollection,
            Action beforeValueAction,
            Action afterValueAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            Debug.Assert(complexValue != null, "complexValue != null");

            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }

            this.IncreaseRecursionDepth();

            // resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata
            IEdmComplexTypeReference complexTypeReference = TypeNameOracle.ResolveAndValidateTypeForComplexValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType, this.WriterValidator).AsComplexOrNull();

            string collectionItemTypeName;
            typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexTypeReference, complexValue.GetAnnotation<SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName);
            Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null");

            Action beforeValueCallbackWithTypeName = beforeValueAction;
            if (typeName != null)
            {
                // The beforeValueAction (if specified) will write the actual property element start.
                // So if we are to write the type attribute, we must postpone that after the start element was written.
                // And so we chain the existing action with our type attribute writing and use that
                // as the before action instead.
                if (beforeValueAction != null)
                {
                    beforeValueCallbackWithTypeName = () =>
                    {
                        beforeValueAction();
                        this.WritePropertyTypeAttribute(typeName);
                    };
                }
                else
                {
                    this.WritePropertyTypeAttribute(typeName);
                }
            }

            bool propertyWritten = this.WriteProperties(
                complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(),
                complexValue.Properties,
                isWritingCollection,
                beforeValueCallbackWithTypeName,
                afterValueAction,
                duplicatePropertyNamesChecker,
                projectedProperties);

            this.DecreaseRecursionDepth();
            return propertyWritten;
        }
コード例 #44
0
        /// <summary>
        /// Reads any next link annotation immediately after the end of a feed.
        /// </summary>
        /// <param name="feed">The feed being read.</param>
        /// <param name="expandedNavigationLinkInfo">The information about the expanded link. This must be non-null if we're reading an expanded feed, and must be null if we're reading a top-level feed.</param>
        /// <param name="duplicatePropertyNamesChecker">The top-level duplicate property names checker, if we're reading a top-level feed.</param>
        internal void ReadNextLinkAnnotationAtFeedEnd(
            ODataFeedBase feed,
            ODataJsonLightReaderNavigationLinkInfo expandedNavigationLinkInfo,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(feed != null, "feed != null");

            // Check for annotations on the feed that occur after the feed itself. (Note: the only allowed one is odata.nextLink, and we fail for anything else.)
            // We do this slightly differently depending on whether the feed was an expanded navigation or a top-level feed.
            if (expandedNavigationLinkInfo != null)
            {
                this.ReadExpandedFeedAnnotationsAtFeedEnd(feed, expandedNavigationLinkInfo);
            }
            else
            {
                Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");

                // Check for feed instance annotations that appear after the feed.
                bool isReordering = this.JsonReader is ReorderingJsonReader;
                this.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, /*forFeedStart*/false, /*readAllFeedProperties*/isReordering);
            }
        }
コード例 #45
0
        public void WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference metadataTypeReference,
            bool isTopLevel,
            bool isOpenPropertyType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(complexValue != null, "complexValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire complex instance;
            // for top-level complex properties we already wrote the object scope (and the context URI when needed).
            if (!isTopLevel)
            {
                this.JsonWriter.StartObjectScope();
            }

            string typeName = complexValue.TypeName;

            if (isTopLevel)
            {
                Debug.Assert(metadataTypeReference == null, "Never expect a metadata type for top-level properties.");
                if (typeName == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightValueSerializer_MissingTypeNameOnComplex);
                }
            }
            else
            {
                // In requests, we allow the property type reference to be null if the type name is specified in the OM
                if (metadataTypeReference == null && !this.WritingResponse && typeName == null && this.Model.IsUserModel())
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueSerializer_NoExpectedTypeOrTypeNameSpecifiedForComplexValueRequest);
                }
            }

            // Resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata.
            IEdmComplexTypeReference complexValueTypeReference = (IEdmComplexTypeReference)TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType);
            Debug.Assert(
                metadataTypeReference == null || complexValueTypeReference == null || EdmLibraryExtensions.IsAssignableFrom(metadataTypeReference, complexValueTypeReference),
                "Complex property types must be the same as or inherit from the ones from metadata (unless open).");

            typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, metadataTypeReference, complexValueTypeReference, isOpenPropertyType);
            if (typeName != null)
            {
                this.ODataAnnotationWriter.WriteODataTypeInstanceAnnotation(typeName);
            }

            // Write custom instance annotations
            this.InstanceAnnotationWriter.WriteInstanceAnnotations(complexValue.InstanceAnnotations);

            // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties.
            this.PropertySerializer.WriteProperties(
                complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(),
                complexValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null /*projectedProperties */);

            // End the object scope which represents the complex instance;
            // for top-level complex properties we already wrote the end object scope.
            if (!isTopLevel)
            {
                this.JsonWriter.EndObjectScope();
            }

            this.DecreaseRecursionDepth();
        }
コード例 #46
0
        private void VerifyInvalidMetadataReferenceProperty(string propertyName)
        {
            string jsonInput = string.Format("{{\"" + JsonLightConstants.ODataPropertyAnnotationSeparatorChar + ODataAnnotationNames.ODataContext + "\":\"http://odata.org/$metadata\"," + "\"{0}\":42}}", propertyName);
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false, true);

            using (ODataJsonLightInputContext inputContext = this.CreateJsonLightInputContext(jsonInput))
            {
                ODataJsonLightEntryAndFeedDeserializer deserializer = new ODataJsonLightEntryAndFeedDeserializer(inputContext);
                deserializer.ReadPayloadStart(ODataPayloadKind.Unsupported, duplicatePropertyNamesChecker, false, false);

                Action readEntryContentAction = () => deserializer.ReadEntryContent(new TestJsonLightReaderEntryState());

                readEntryContentAction
                    .ShouldThrow<ODataException>("the property name \"{0}\" contains a hash but is not a valid URI or URI fragment", propertyName)
                    .WithMessage(ErrorStrings.ValidationUtils_InvalidMetadataReferenceProperty(propertyName));
            }
        }
コード例 #47
0
        private void AssertDuplicateMetadataReferencePropertyFails(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            string payload = "{\"#action\":42, \"#action\":43}";

            using (ODataJsonLightInputContext inputContext = this.CreateJsonLightInputContext(payload))
            {
                ODataJsonLightDeserializer deserializer = new ODataJsonLightPropertyAndValueDeserializer(inputContext);
                AdvanceReaderToFirstProperty(deserializer.JsonReader);

                deserializer.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    (propertyName) => null,
                    (propertyParsingResult, propertyName) =>
                    {
                        propertyParsingResult.Should().Be(ODataJsonLightDeserializer.PropertyParsingResult.MetadataReferenceProperty, "parsing JSON object '{0}'", payload);
                        propertyName.Should().Be("#action", "reported name is wrong for JSON object '{0}'", payload);

                        deserializer.JsonReader.Should().BeOn(JsonNodeType.PrimitiveValue, 42);

                        deserializer.JsonReader.Read();
                        deserializer.JsonReader.NodeType.Should().Be(JsonNodeType.Property);
                    });

                Action readDuplicateProperty = () => deserializer.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    (propertyName) => null,
                    (propertyParsingResult, propertyName) => { });

                readDuplicateProperty.ShouldThrow<ODataException>("two metadata reference properties were encountered with the same name").WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed("#action"));
            }
        }
コード例 #48
0
 public void TwoMetadataReferencePropertiesShouldStillResultInDuplicationExceptionIfAllowingDuplicates()
 {
     DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(allowDuplicateProperties: true, isResponse: true);
     this.AssertDuplicateMetadataReferencePropertyFails(duplicatePropertyNamesChecker);
 }
コード例 #49
0
 public void ParsingDuplicateODataTypeAnnotationTargetingCustomInstanceAnnotationShouldFail()
 {
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => this.RunPropertyParsingTest("{\"[email protected]\":\"#typename\",\"[email protected]\":\"#typename\"}", ODataJsonLightDeserializer.PropertyParsingResult.CustomInstanceAnnotation, "custom.type",
         null, this.ReadODataTypePropertyAnnotation, duplicatePropertyNamesChecker);
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationForInstanceAnnotationNotAllowed("odata.type", "custom.annotation"));
 }
コード例 #50
0
 public void ParsingDuplicateCustomInstanceAnnotationShouldFail2()
 {
     this.messageReaderSettings.ShouldIncludeAnnotation = ODataUtils.CreateAnnotationFilter("*");
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => this.RunPropertyParsingTest("{\"@custom.type\":\"typename\",\"@custom.type\":\"typename\"}", ODataJsonLightDeserializer.PropertyParsingResult.CustomInstanceAnnotation, "custom.type",
         null, this.ReadODataTypePropertyAnnotation, duplicatePropertyNamesChecker);
     action();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed("custom.type"));
 }
コード例 #51
0
 public void ParsingDuplicateODataInstanceAnnotationShouldFail()
 {
     var duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(false, true);
     Action action = () => this.RunPropertyParsingTest("{\"@odata.deltaLink\":\"url\",\"@odata.deltaLink\":\"url\"}", ODataJsonLightDeserializer.PropertyParsingResult.ODataInstanceAnnotation, "odata.deltaLink",
         null, this.ReadODataTypePropertyAnnotation, duplicatePropertyNamesChecker);
     action();
     action.ShouldThrow<ODataException>().WithMessage(ErrorStrings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed("odata.deltaLink"));
 }
コード例 #52
0
        /// <summary>
        /// Reads instance annotation in the entry object.
        /// </summary>
        /// <param name="annotationName">The name of the instance annotation found.</param>
        /// <param name="anyPropertyFound">true if a non-annotation property has already been encountered.</param>
        /// <param name="typeAnnotationFound">true if the 'odata.type' annotation has already been encountered, or should have been by now.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the entry being read.</param>
        /// <returns>The value of the annotation.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue         The value of the instance annotation property
        ///                 JsonNodeType.StartObject
        ///                 JsonNodeType.StartArray
        /// Post-Condition: JsonNodeType.EndObject              The end of the entry object
        ///                 JsonNodeType.Property               The next property after the instance annotation
        /// </remarks>
        internal object ReadEntryInstanceAnnotation(string annotationName, bool anyPropertyFound, bool typeAnnotationFound, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)");
            this.AssertJsonCondition(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, JsonNodeType.StartArray);

            switch (annotationName)
            {
                case ODataAnnotationNames.ODataType:   // 'odata.type'
                    if (!typeAnnotationFound)
                    {
                        return this.ReadODataTypeAnnotationValue();
                    }

                    // We already read the odata.type if it was the first property in ReadEntryStart, so any other occurrence means
                    // that it was not the first property.
                    throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_EntryTypeAnnotationNotFirst);

                case ODataAnnotationNames.ODataId:   // 'odata.id'
                    if (anyPropertyFound)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_EntryInstanceAnnotationPrecededByProperty(annotationName));
                    }

                    return this.ReadAnnotationStringValueAsUri(annotationName);

                case ODataAnnotationNames.ODataETag:   // 'odata.etag'
                    if (anyPropertyFound)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_EntryInstanceAnnotationPrecededByProperty(annotationName));
                    }

                    return this.ReadAndValidateAnnotationStringValue(annotationName);

                case ODataAnnotationNames.ODataEditLink:    // 'odata.editLink'
                case ODataAnnotationNames.ODataReadLink:    // 'odata.readLink'
                case ODataAnnotationNames.ODataMediaEditLink:   // 'odata.mediaEditLink'
                case ODataAnnotationNames.ODataMediaReadLink:   // 'odata.mediaReadLink'
                    return this.ReadAndValidateAnnotationStringValueAsUri(annotationName);

                case ODataAnnotationNames.ODataMediaContentType:  // 'odata.mediaContentType'
                case ODataAnnotationNames.ODataMediaETag:  // 'odata.mediaEtag'
                    return this.ReadAndValidateAnnotationStringValue(annotationName);

                default:
                    ODataAnnotationNames.ValidateIsCustomAnnotationName(annotationName);
                    Debug.Assert(
                        !this.MessageReaderSettings.ShouldSkipAnnotation(annotationName),
                        "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(annotationName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                    return this.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, annotationName);
            }
        }
コード例 #53
0
        /// <summary>
        /// Reads the value of a feed annotation (count or next link).
        /// </summary>
        /// <param name="annotationName">The name of the annotation found.</param>
        /// <param name="feed">The feed to read the annotation for; if non-null, the annotation value will be assigned to the feed.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker instance.</param>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue         The value of the annotation
        /// Post-Condition: JsonNodeType.EndObject              The end of the feed object
        ///                 JsonNodeType.Property               The next annotation after the current annotation
        /// </remarks>
        internal void ReadAndApplyFeedInstanceAnnotationValue(string annotationName, ODataFeedBase feed, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)");
            Debug.Assert(feed != null, "feed != null");

            switch (annotationName)
            {
                case ODataAnnotationNames.ODataCount:
                    feed.Count = this.ReadAndValidateAnnotationAsLongForIeee754Compatible(ODataAnnotationNames.ODataCount);
                    break;

                case ODataAnnotationNames.ODataNextLink:
                    feed.NextPageLink = this.ReadAndValidateAnnotationStringValueAsUri(ODataAnnotationNames.ODataNextLink);
                    break;

                case ODataAnnotationNames.ODataDeltaLink:
                    feed.DeltaLink = this.ReadAndValidateAnnotationStringValueAsUri(ODataAnnotationNames.ODataDeltaLink);
                    break;

                default:
                    ODataAnnotationNames.ValidateIsCustomAnnotationName(annotationName);
                    Debug.Assert(
                        !this.MessageReaderSettings.ShouldSkipAnnotation(annotationName),
                        "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(annotationName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                    object instanceAnnotationValue = this.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, annotationName);
                    feed.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotationName, instanceAnnotationValue.ToODataValue()));
                    break;
            }
        }
コード例 #54
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);
            }
        }
コード例 #55
0
        /// <summary>
        /// Write the given collection of properties.
        /// </summary>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param>
        /// <param name="cachedProperties">Collection of cached properties for the entry.</param>
        /// <param name="isWritingCollection">true if we are writing a top level collection instead of an entry.</param>
        /// <param name="beforePropertiesAction">Action which is called before the properties are written, if there are any property.</param>
        /// <param name="afterPropertiesAction">Action which is called after the properties are written, if there are any property.</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>
        /// <returns>true if anything was written, false otherwise.</returns>
        internal bool WriteProperties(
            IEdmStructuredType owningType,
            IEnumerable<ODataProperty> cachedProperties,
            bool isWritingCollection,
            Action beforePropertiesAction,
            Action afterPropertiesAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            if (cachedProperties == null)
            {
                return false;
            }

            bool propertyWritten = false;
            foreach (ODataProperty property in cachedProperties)
            {
                propertyWritten |= this.WriteProperty(
                    property,
                    owningType,
                    /*isTopLevel*/false,
                    isWritingCollection,
                    propertyWritten ? null : beforePropertiesAction,
                    duplicatePropertyNamesChecker,
                    projectedProperties);
            }

            if (afterPropertiesAction != null && propertyWritten)
            {
                afterPropertiesAction();
            }

            return propertyWritten;
        }
コード例 #56
0
        /// <summary>
        /// Writes property names and value pairs.
        /// </summary>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param>
        /// <param name="properties">The enumeration of properties to write out.</param>
        /// <param name="isComplexValue">
        /// Whether the properties are being written for complex value. Also used for detecting whether stream properties
        /// are allowed as 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>
        internal void WriteProperties(
            IEdmStructuredType owningType,
            IEnumerable<ODataProperty> properties,
            bool isComplexValue,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            if (properties == null)
            {
                return;
            }

            foreach (ODataProperty property in properties)
            {
                this.WriteProperty(
                    property,
                    owningType,
                    false /* isTopLevel */,
                    !isComplexValue,
                    duplicatePropertyNamesChecker,
                    projectedProperties);
            }
        }
コード例 #57
0
        /// <summary>
        /// Writes a single property in ATOM format.
        /// </summary>
        /// <param name="property">The property to write out.</param>
        /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param>
        /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param>
        /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param>
        /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</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>
        /// <returns>true if the property was actually written, false otherwise.</returns>
        private bool WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            bool isWritingCollection,
            Action beforePropertyAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            WriterValidationUtils.ValidatePropertyNotNull(property);

            object value = property.Value;
            string propertyName = property.Name;
            //// TODO: If we implement type conversions the value needs to be converted here
            ////       since the next method call needs to know if the value is a string or not in some cases.

            ODataComplexValue complexValue = value as ODataComplexValue;
            ProjectedPropertiesAnnotation complexValueProjectedProperties = null;
            if (!ShouldWritePropertyInContent(projectedProperties, propertyName))
            {
                return false;
            }

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

            if (value is ODataStreamReferenceValue)
            {
                throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
            }

            // Null property value.
            if (value == null)
            {
                this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction);
                return true;
            }

            bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null;
            if (isOpenPropertyType)
            {
                ValidationUtils.ValidateOpenPropertyValue(propertyName, value);
            }

            if (complexValue != null)
            {
                return this.WriteComplexValueProperty(
                    complexValue,
                    propertyName,
                    isTopLevel,
                    isWritingCollection,
                    beforePropertyAction,
                    propertyTypeReference,
                    isOpenPropertyType,
                    complexValueProjectedProperties);
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;
            if (collectionValue != null)
            {
                this.WriteCollectionValueProperty(
                    collectionValue,
                    propertyName,
                    isTopLevel,
                    isWritingCollection,
                    beforePropertyAction,
                    propertyTypeReference,
                    isOpenPropertyType);

                return true;
            }

            // If the value isn't one of the value types tested for already, it must be a non-null primitive or enum type.
            this.WritePropertyStart(beforePropertyAction, property, isWritingCollection, isTopLevel);
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation<SerializationTypeNameAnnotation>();
            ODataEnumValue enumValue = value as ODataEnumValue;
            if (enumValue != null)
            {
                this.WriteEnumValue(enumValue, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation);
            }
            else
            {
                this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation);
            }

            this.WritePropertyEnd();
            return true;
        }
コード例 #58
0
        /// <summary>
        /// Read a complex value from the reader.
        /// </summary>
        /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param>
        /// <returns>The value read from the payload.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element   - the element to read the value for.
        ///                  XmlNodeType.Attribute - an attribute on the element to read the value for.
        /// Post-Condition:  XmlNodeType.EndElement - the element has been read.
        ///                  
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataComplexValue ReadComplexValue(
            IEdmComplexTypeReference complexTypeReference, 
            string payloadTypeName, 
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);

            this.IncreaseRecursionDepth();

            ODataComplexValue complexValue = new ODataComplexValue();
            IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition;

            // If we have a metadata type for the complex value, use that type name
            // otherwise use the type name from the payload (if there was any).
            complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName();
            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            // Move to the element (so that if we were on an attribute we can test the element for being empty)
            this.XmlReader.MoveToElement();

            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }

            ReadOnlyEnumerable<ODataProperty> properties = new ReadOnlyEnumerable<ODataProperty>();
            this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker);
            complexValue.Properties = properties;

            this.AssertXmlCondition(true, XmlNodeType.EndElement);
            Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values.");

            this.DecreaseRecursionDepth();

            return complexValue;
        }
コード例 #59
0
        /// <summary>
        /// Writes a stream property to the ATOM payload
        /// </summary>
        /// <param name="streamProperty">The stream property to create the payload for.</param>
        /// <param name="owningType">The <see cref="IEdmEntityType"/> instance for which the stream property defined on.</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>
        internal void WriteStreamProperty(
            ODataProperty streamProperty,
            IEdmEntityType owningType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(streamProperty != null, "Stream property must not be null.");
            Debug.Assert(streamProperty.Value != null, "The media resource of the stream property must not be null.");

            WriterValidationUtils.ValidatePropertyNotNull(streamProperty);
            string propertyName = streamProperty.Name;
            if (projectedProperties.ShouldSkipProperty(propertyName))
            {
                return;
            }

            WriterValidationUtils.ValidateProperty(streamProperty);
            duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty);
            IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType);
            WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, this.Version, this.WritingResponse);
            ODataStreamReferenceValue streamReferenceValue = (ODataStreamReferenceValue)streamProperty.Value;
            if (owningType != null && owningType.IsOpen && edmProperty == null)
            {
                ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamReferenceValue);
            }

            AtomStreamReferenceMetadata streamReferenceMetadata = streamReferenceValue.GetAnnotation<AtomStreamReferenceMetadata>();
            string contentType = streamReferenceValue.ContentType;
            string linkTitle = streamProperty.Name;

            Uri readLink = streamReferenceValue.ReadLink;
            if (readLink != null)
            {
                string readLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false);

                AtomLinkMetadata readLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.SelfLink;
                AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(readLinkMetadata, readLinkRelation, readLink, linkTitle, contentType);
                this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, null /* etag */);
            }

            Uri editLink = streamReferenceValue.EditLink;
            if (editLink != null)
            {
                string editLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true);

                AtomLinkMetadata editLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.EditLink;
                AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(editLinkMetadata, editLinkRelation, editLink, linkTitle, contentType);
                this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, streamReferenceValue.ETag);
            }
        }
コード例 #60
0
            /// <summary>
            /// Constructor to create a new entry scope.
            /// </summary>
            /// <param name="state">The writer state of this scope.</param>
            /// <param name="entry">The entry for the new scope.</param>
            /// <param name="serializationInfo">The serialization info for the current entry.</param>
            /// <param name="navigationSource">The navigation source we are going to write entities for.</param>
            /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param>
            /// <param name="writerBehavior">The <see cref="ODataWriterBehavior"/> instance controlling the behavior of the writer.</param>
            /// <param name="selectedProperties">The selected properties of this scope.</param>
            /// <param name="odataUri">The ODataUri info of this scope.</param>
            protected DeltaEntryScope(WriterState state, ODataItem entry, ODataFeedAndEntrySerializationInfo serializationInfo, IEdmNavigationSource navigationSource, IEdmEntityType entityType, ODataWriterBehavior writerBehavior, SelectedPropertiesNode selectedProperties, ODataUri odataUri)
                : base(state, entry, navigationSource, entityType, selectedProperties, odataUri)
            {
                Debug.Assert(entry != null, "entry != null");
                Debug.Assert(
                    state == WriterState.DeltaEntry && entry is ODataEntry ||
                    state == WriterState.DeltaDeletedEntry && entry is ODataDeltaDeletedEntry,
                    "entry must be either DeltaEntry or DeltaDeletedEntry.");
                Debug.Assert(writerBehavior != null, "writerBehavior != null");

                this.duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(writerBehavior.AllowDuplicatePropertyNames, /*writingResponse*/ true);
                this.serializationInfo = serializationInfo;
            }