/// <summary> /// Validates a stream reference property. /// </summary> /// <param name="streamProperty">The stream property to check.</param> /// <param name="structuredType">The owning type of the stream property or null if no metadata is available.</param> /// <param name="streamEdmProperty">The stream property defined by the model.</param> public void ValidateStreamReferenceProperty(ODataProperty streamProperty, IEdmStructuredType structuredType, IEdmProperty streamEdmProperty) { ReaderValidationUtils.ValidateStreamReferenceProperty( streamProperty, structuredType, streamEdmProperty, settings.ThrowOnUndeclaredPropertyForNonOpenType); }
private ODataEntityReferenceLink ReadSingleEntityReferenceLink() { if (base.JsonReader.NodeType != JsonNodeType.StartObject) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_EntityReferenceLinkMustBeObjectValue(base.JsonReader.NodeType)); } base.JsonReader.ReadStartObject(); ODataEntityReferenceLink link = new ODataEntityReferenceLink(); while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("uri", strB) == 0) { if (link.Url != null) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_MultipleUriPropertiesInEntityReferenceLink); } string uriFromPayload = base.JsonReader.ReadStringValue("uri"); if (uriFromPayload == null) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_EntityReferenceLinkUriCannotBeNull); } link.Url = base.ProcessUriFromPayload(uriFromPayload); } else { base.JsonReader.SkipValue(); } } ReaderValidationUtils.ValidateEntityReferenceLink(link); base.JsonReader.ReadEndObject(); return(link); }
/// <summary> /// Asynchronous implementation of the collection reader logic when in state 'Start'. /// </summary> /// <param name="propertyAndAnnotationCollector">The duplicate property names checker for the top-level scope.</param> /// <returns> /// A task that represents the asynchronous read operation. /// The value of the TResult parameter contains 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 async Task <bool> ReadAtStartImplementationAsynchronously(PropertyAndAnnotationCollector propertyAndAnnotationCollector) { Debug.Assert(propertyAndAnnotationCollector != null, "propertyAndAnnotationCollector != 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 Tuple <ODataCollectionStart, IEdmTypeReference> readCollectionStartResult = await this.jsonLightCollectionDeserializer.ReadCollectionStartAsync( propertyAndAnnotationCollector, this.IsReadingNestedPayload, this.ExpectedItemTypeReference).ConfigureAwait(false); ODataCollectionStart collectionStart = readCollectionStartResult.Item1; actualItemTypeReference = readCollectionStartResult.Item2; if (actualItemTypeReference != null) { this.ExpectedItemTypeReference = actualItemTypeReference; } await this.jsonLightCollectionDeserializer.JsonReader.ReadStartArrayAsync() .ConfigureAwait(false); this.EnterScope(ODataCollectionReaderState.CollectionStart, collectionStart); return(true); }
/// <summary> /// Reads the headers of a part. /// </summary> /// <param name="contentId">Content-ID read from changeset header, null if changeset part detected</param> /// <returns>true if the start of a changeset part was detected; otherwise false.</returns> internal bool ProcessPartHeader(out string contentId) { Debug.Assert(this.batchEncoding != null, "Batch encoding should have been established on first call to SkipToBoundary."); bool isChangeSetPart; ODataBatchOperationHeaders headers = this.ReadPartHeaders(out isChangeSetPart); contentId = null; if (isChangeSetPart) { // determine the changeset boundary and the changeset encoding from the content type header this.DetermineChangesetBoundaryAndEncoding(headers[ODataConstants.ContentTypeHeader]); if (this.changesetEncoding == null) { // NOTE: No changeset encoding was specified in the changeset's content type header. // Determine the changeset encoding from the first bytes in the changeset. // NOTE: We do not have to skip over the potential preamble of the encoding // because the batch reader will skip over everything (incl. the preamble) // until it finds the first changeset (or batch) boundary this.changesetEncoding = this.DetectEncoding(); } // Verify that we only allow single byte encodings and UTF-8 for now. ReaderValidationUtils.ValidateEncodingSupportedInBatch(this.changesetEncoding); } else if (this.ChangeSetBoundary != null) { headers.TryGetValue(ODataConstants.ContentIdHeader, out contentId); } return(isChangeSetPart); }
internal static object ConvertValue( object value, IEdmPrimitiveTypeReference primitiveTypeReference, ODataMessageReaderSettings messageReaderSettings, bool validateNullValue, string propertyName, ODataPayloadValueConverter converter) { Debug.Assert(primitiveTypeReference != null, "primitiveTypeReference != null"); if (value == null) { // Only primitive type references are validated. Core model is sufficient. ReaderValidationUtils.ValidateNullValue( EdmCoreModel.Instance, primitiveTypeReference, messageReaderSettings, validateNullValue, propertyName); return(null); } value = converter.ConvertFromPayloadValue(value, primitiveTypeReference); // otherwise just return the value without doing any conversion return(value); }
/// <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); }
/// <summary> /// Tries to read a null value from the JSON reader. /// </summary> /// <param name="jsonReader">The JSON reader to read from.</param> /// <param name="inputContext">The input context with all the settings.</param> /// <param name="expectedTypeReference">The expected type reference of the value.</param> /// <param name="validateNullValue">true to validate null values; otherwise false.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param> /// <param name="isDynamicProperty">Indicates whether the property is dynamic or unknown.</param> /// <returns>true if a null value could be read from the JSON reader; otherwise false.</returns> /// <remarks>If the method detects a null value it will read it (position the reader after the null value); /// otherwise the reader does not move.</remarks> internal static bool TryReadNullValue( BufferingJsonReader jsonReader, ODataInputContext inputContext, IEdmTypeReference expectedTypeReference, bool validateNullValue, string propertyName, bool?isDynamicProperty = null) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(inputContext != null, "inputContext != null"); if (jsonReader.NodeType == JsonNodeType.PrimitiveValue && jsonReader.Value == null) { jsonReader.ReadNext(); // NOTE: when reading a null value we will never ask the type resolver (if present) to resolve the // type; we always fall back to the expected type. ReaderValidationUtils.ValidateNullValue( inputContext.Model, expectedTypeReference, inputContext.MessageReaderSettings, validateNullValue, inputContext.Version, propertyName, isDynamicProperty); return(true); } return(false); }
private void ReadPropertiesImplementation(IEdmStructuredType structuredType, List <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { if (!base.XmlReader.IsEmptyElement) { base.XmlReader.ReadStartElement(); do { switch (base.XmlReader.NodeType) { case XmlNodeType.Element: if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace)) { IEdmProperty property = null; bool flag = false; bool ignoreProperty = false; if (structuredType != null) { property = ReaderValidationUtils.ValidateValuePropertyDefined(base.XmlReader.LocalName, structuredType, base.MessageReaderSettings, out ignoreProperty); if ((property != null) && (property.PropertyKind == EdmPropertyKind.Navigation)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(property.Name, structuredType)); } flag = property == null; } if (ignoreProperty) { base.XmlReader.Skip(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = (base.ReadingResponse || (property == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property); ODataProperty property2 = this.ReadProperty((property == null) ? null : property.Type, nullValueReadBehaviorKind, epmPresent); if (property2 != null) { if (flag) { ValidationUtils.ValidateOpenPropertyValue(property2.Name, property2.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property2); properties.Add(property2); } } } else { base.XmlReader.Skip(); } break; case XmlNodeType.EndElement: break; default: base.XmlReader.Skip(); break; } }while (base.XmlReader.NodeType != XmlNodeType.EndElement); } }
/// <summary> /// Reads the next <see cref="ODataItem"/> from the message payload. /// </summary> /// <returns>true if more items were read; otherwise false.</returns> private bool ReadImplementation() { bool result; switch (this.State) { case ODataReaderState.Start: result = this.ReadAtStartImplementation(); break; case ODataReaderState.FeedStart: result = this.ReadAtFeedStartImplementation(); break; case ODataReaderState.FeedEnd: result = this.ReadAtFeedEndImplementation(); break; case ODataReaderState.EntryStart: this.IncreaseEntryDepth(); result = this.ReadAtEntryStartImplementation(); break; case ODataReaderState.EntryEnd: this.DecreaseEntryDepth(); result = this.ReadAtEntryEndImplementation(); break; case ODataReaderState.NavigationLinkStart: result = this.ReadAtNavigationLinkStartImplementation(); break; case ODataReaderState.NavigationLinkEnd: result = this.ReadAtNavigationLinkEndImplementation(); break; case ODataReaderState.EntityReferenceLink: result = this.ReadAtEntityReferenceLink(); break; case ODataReaderState.Exception: // fall through case ODataReaderState.Completed: throw new ODataException(Strings.ODataReaderCore_NoReadCallsAllowed(this.State)); default: Debug.Assert(false, "Unsupported reader state " + this.State + " detected."); throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ODataReaderCore_ReadImplementation)); } if ((this.State == ODataReaderState.EntryStart || this.State == ODataReaderState.EntryEnd) && this.Item != null) { ReaderValidationUtils.ValidateEntry(this.CurrentEntry); } return(result); }
private bool TryReadNullValue(IEdmTypeReference expectedTypeReference, bool validateNullValue) { if ((base.JsonReader.NodeType == JsonNodeType.PrimitiveValue) && (base.JsonReader.Value == null)) { base.JsonReader.ReadNext(); ReaderValidationUtils.ValidateNullValue(base.Model, expectedTypeReference, base.MessageReaderSettings, validateNullValue, base.Version); return(true); } return(false); }
/// <summary> /// Validate a null value. /// </summary> /// <param name="expectedTypeReference">The expected type of the null value.</param> /// <param name="validateNullValue">true to validate the null value; false to only check whether the type is /// supported.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable /// (used for error reporting).</param> /// <param name="isDynamicProperty">Indicates whether the property is dynamic or unknown.</param> public void ValidateNullValue(IEdmTypeReference expectedTypeReference, bool validateNullValue, string propertyName, bool?isDynamicProperty) { if (settings.ThrowIfTypeConflictsWithMetadata) { ReaderValidationUtils.ValidateNullValue(expectedTypeReference, settings.EnablePrimitiveTypeConversion, validateNullValue, propertyName, isDynamicProperty); } }
private ODataEntityReferenceLink ReadUriElement() { ODataEntityReferenceLink link = new ODataEntityReferenceLink(); Uri xmlBaseUri = base.XmlReader.XmlBaseUri; string uriFromPayload = base.XmlReader.ReadElementValue(); Uri uri2 = base.ProcessUriFromPayload(uriFromPayload, xmlBaseUri); link.Url = uri2; ReaderValidationUtils.ValidateEntityReferenceLink(link); return(link); }
/// <summary> /// Read a null value from the payload. /// </summary> /// <param name="expectedTypeReference">The expected type reference (for validation purposes).</param> /// <param name="validateNullValue">true to validate the value against the <paramref name="expectedTypeReference"/>.</param> /// <returns>The null value.</returns> private object ReadNullValue(IEdmTypeReference expectedTypeReference, bool validateNullValue) { // The m:null attribute has a precedence over the content of the element, thus if we find m:null='true' we ignore the content of the element. this.XmlReader.SkipElementContent(); // NOTE: when reading a null value we will never ask the type resolver (if present) to resolve the // type; we always fall back to the expected type. ReaderValidationUtils.ValidateNullValue(this.Model, expectedTypeReference, this.MessageReaderSettings, validateNullValue, this.Version); return(null); }
/// <summary> /// Reads a top-level entity reference link - implementation of the actual functionality. /// </summary> /// <param name="navigationProperty">The navigation property for which to read the entity reference links.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use for the top-level scope.</param> /// <returns>An <see cref="ODataEntityReferenceLink"/> representing the read entity reference link.</returns> private ODataEntityReferenceLink ReadEntityReferenceLinkImplementation(IEdmNavigationProperty navigationProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); if (this.JsonLightInputContext.ReadingResponse) { // Validate the metadata URI parsed from the payload against the expected navigation property. ReaderValidationUtils.ValidateEntityReferenceLinkMetadataUri(this.MetadataUriParseResult, navigationProperty); } return(this.ReadSingleEntityReferenceLink(duplicatePropertyNamesChecker, /*topLevel*/ true)); }
/// <summary> /// Constructor. /// </summary> /// <param name="rawInputContext">The input context to read the content from.</param> /// <param name="encoding">The encoding for the underlying stream.</param> internal ODataAsynchronousReader(ODataRawInputContext rawInputContext, Encoding encoding) { Debug.Assert(rawInputContext != null, "rawInputContext != null"); // Currently we only support single-byte UTF8 in async reader. if (encoding != null) { ReaderValidationUtils.ValidateEncodingSupportedInAsync(encoding); } this.rawInputContext = rawInputContext; }
private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue) { object obj2; SerializationTypeNameAnnotation annotation; EdmTypeKind kind; JsonNodeType nodeType = base.JsonReader.NodeType; if (nodeType == JsonNodeType.StartArray) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType)); } if (this.TryReadNullValue(expectedTypeReference, validateNullValue)) { return(null); } string payloadTypeName = this.FindTypeNameInPayload(); IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, null, expectedTypeReference, payloadTypeName, base.Model, base.MessageReaderSettings, base.Version, new Func <EdmTypeKind>(this.GetNonEntityValueKind), out kind, out annotation); switch (kind) { case EdmTypeKind.Primitive: { IEdmPrimitiveTypeReference reference2 = (type == null) ? null : type.AsPrimitive(); if ((payloadTypeName != null) && !reference2.IsSpatial()) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName)); } obj2 = this.ReadPrimitiveValueImplementation(reference2, validateNullValue); break; } case EdmTypeKind.Complex: obj2 = this.ReadComplexValueImplementation((type == null) ? null : type.AsComplex(), payloadTypeName, annotation, duplicatePropertyNamesChecker); break; case EdmTypeKind.Collection: { IEdmCollectionTypeReference collectionValueTypeReference = ValidationUtils.ValidateCollectionType(type); obj2 = this.ReadCollectionValueImplementation(collectionValueTypeReference, payloadTypeName, annotation); break; } default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataJsonPropertyAndValueDeserializer_ReadPropertyValue)); } if (collectionValidator != null) { string collectionItemTypeName = ODataJsonReaderUtils.GetPayloadTypeName(obj2); collectionValidator.ValidateCollectionItem(collectionItemTypeName, kind); } return(obj2); }
/// <summary> /// Ensure that a batch encoding exists; if not, detect it from the first couple of bytes of the stream. /// </summary> /// <param name="stream">The stream to read.</param> private void EnsureBatchEncoding(Stream stream) { // If no batch encoding is specified we detect it from the first bytes in the buffer. if (this.batchEncoding == null) { // NOTE: The batch encoding will only ever be null on the first call to this method which // happens before the batch reader skips to the first boundary. this.batchEncoding = this.DetectEncoding(stream); } // Verify that we only allow single byte encodings and UTF-8 for now. ReaderValidationUtils.ValidateEncodingSupportedInBatch(this.batchEncoding); }
/// <summary> /// Read an entity reference link. /// </summary> /// <returns>An instance of <see cref="ODataEntityReferenceLink"/> which was read.</returns> /// <remarks> /// Pre-Condition: any node - This method will throw if the node type is not a StartObject node /// Post-Condition: any node /// </remarks> private ODataEntityReferenceLink ReadSingleEntityReferenceLink() { this.JsonReader.AssertNotBuffering(); if (this.JsonReader.NodeType != JsonNodeType.StartObject) { // entity reference link has to be an object throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_EntityReferenceLinkMustBeObjectValue(this.JsonReader.NodeType)); } this.JsonReader.ReadStartObject(); ODataEntityReferenceLink entityReferenceLink = new ODataEntityReferenceLink(); while (this.JsonReader.NodeType == JsonNodeType.Property) { // read the 'uri' property string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataUriName, propertyName) == 0) { if (entityReferenceLink.Url != null) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_MultipleUriPropertiesInEntityReferenceLink); } // read the value of the 'uri' property string uriString = this.JsonReader.ReadStringValue(JsonConstants.ODataUriName); if (uriString == null) { throw new ODataException(Strings.ODataJsonEntityReferenceLinkDeserializer_EntityReferenceLinkUriCannotBeNull); } entityReferenceLink.Url = this.ProcessUriFromPayload(uriString); } else { // Skip unrecognized properties this.JsonReader.SkipValue(); } } ReaderValidationUtils.ValidateEntityReferenceLink(entityReferenceLink); // end of the entity reference link object this.JsonReader.ReadEndObject(); this.JsonReader.AssertNotBuffering(); return(entityReferenceLink); }
/// <summary> /// Reads a property. /// </summary> /// <param name="isTop">whether it is the top level</param> /// <param name="expectedPropertyName">The expected property name to be read from the payload (or null if no expected property name was specified).</param> /// <param name="expectedPropertyTypeReference">The expected type reference of the property value.</param> /// <param name="nullValueReadBehaviorKind">Behavior to use when reading null value for the property.</param> /// <returns>The ODataProperty representing the property in question; if null is returned from this method it means that the property is to be ignored.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The XML element representing the property to read. /// Note that the method does NOT check for the property name neither it resolves the property against metadata. /// Post-Condition: Any - The node after the property. /// </remarks> private ODataProperty ReadProperty( bool isTop, string expectedPropertyName, IEdmTypeReference expectedPropertyTypeReference, ODataNullValueBehaviorKind nullValueReadBehaviorKind) { Debug.Assert( expectedPropertyTypeReference == null || expectedPropertyTypeReference.IsODataPrimitiveTypeKind() || expectedPropertyTypeReference.IsODataEnumTypeKind() || expectedPropertyTypeReference.IsODataComplexTypeKind() || expectedPropertyTypeReference.IsNonEntityCollectionType(), "Only primitive, Enum, complex and collection types can be read by this method."); this.AssertXmlCondition(XmlNodeType.Element); this.XmlReader.AssertNotBuffering(); ODataProperty property = new ODataProperty(); string propertyName = null; if (!isTop) { propertyName = this.XmlReader.LocalName; ValidationUtils.ValidatePropertyName(propertyName); ReaderValidationUtils.ValidateExpectedPropertyName(expectedPropertyName, propertyName); } property.Name = propertyName; object propertyValue = this.ReadNonEntityValueImplementation( expectedPropertyTypeReference, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, propertyName); if (nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue && propertyValue == null) { property = null; } else { property.Value = propertyValue; } // Read past the end tag of the property or the start tag if the element is empty. this.XmlReader.Read(); this.XmlReader.AssertNotBuffering(); return(property); }
private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent) { string itemTypeNameFromCollection; bool flag; SerializationTypeNameAnnotation annotation; EdmTypeKind kind2; this.ReadNonEntityValueAttributes(out itemTypeNameFromCollection, out flag); if (flag) { return(this.ReadNullValue(expectedTypeReference, validateNullValue)); } bool flag2 = false; if ((collectionValidator != null) && (itemTypeNameFromCollection == null)) { itemTypeNameFromCollection = collectionValidator.ItemTypeNameFromCollection; flag2 = collectionValidator.ItemTypeKindFromCollection != EdmTypeKind.None; } IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, edmStringType, expectedTypeReference, itemTypeNameFromCollection, base.Model, base.MessageReaderSettings, base.Version, new Func <EdmTypeKind>(this.GetNonEntityValueKind), out kind2, out annotation); if (flag2) { annotation = new SerializationTypeNameAnnotation { TypeName = null }; } if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(itemTypeNameFromCollection, kind2); } switch (kind2) { case EdmTypeKind.Primitive: return(this.ReadPrimitiveValue(type.AsPrimitive())); case EdmTypeKind.Complex: return(this.ReadComplexValue((type == null) ? null : type.AsComplex(), itemTypeNameFromCollection, annotation, duplicatePropertyNamesChecker, epmPresent)); case EdmTypeKind.Collection: { IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(type); return(this.ReadCollectionValue(collectionTypeReference, itemTypeNameFromCollection, annotation)); } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue)); }
/// <summary> /// Resolves and validates the payload type against the expected type and returns the target type. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectStructuredType">This value indicates if a structured type is expected to be return. /// True for structured type, false for non-structured type, null for indetermination.</param> /// <param name="defaultPrimitivePayloadType">The default payload type if none is specified in the payload; /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="model">The model to use.</param> /// <param name="typeKindFromPayloadFunc">A func to compute the type kind from the payload shape if it could not be determined from the expected type or the payload type.</param> /// <param name="targetTypeKind">The target type kind to be used to read the payload.</param> /// <param name="typeAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns> /// The target type reference to use for parsing the value. /// If there is no user specified model, this will return null. /// If there is a user specified model, this method never returns null. /// </returns> /// <remarks> /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead. /// </remarks> public IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind expectedTypeKind, bool?expectStructuredType, IEdmType defaultPrimitivePayloadType, IEdmTypeReference expectedTypeReference, string payloadTypeName, IEdmModel model, Func <EdmTypeKind> typeKindFromPayloadFunc, out EdmTypeKind targetTypeKind, out ODataTypeAnnotation typeAnnotation) { return(ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType( expectedTypeKind, expectStructuredType, defaultPrimitivePayloadType, expectedTypeReference, payloadTypeName, model, settings.ClientCustomTypeResolver, settings.ThrowIfTypeConflictsWithMetadata, settings.EnablePrimitiveTypeConversion, typeKindFromPayloadFunc, out targetTypeKind, out typeAnnotation)); }
/// <summary> /// Reads a property. /// </summary> /// <param name="expectedPropertyName">The expected property name to be read from the payload (or null if no expected property name was specified).</param> /// <param name="expectedPropertyTypeReference">The expected type reference of the property value.</param> /// <param name="nullValueReadBehaviorKind">Behavior to use when reading null value for the property.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The ODataProperty representing the property in question; if null is returned from this method it means that the property is to be ignored.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The XML element representing the property to read. /// Note that the method does NOT check for the property name neither it resolves the property against metadata. /// Post-Condition: Any - The node after the property. /// </remarks> private ODataProperty ReadProperty( string expectedPropertyName, IEdmTypeReference expectedPropertyTypeReference, ODataNullValueBehaviorKind nullValueReadBehaviorKind, bool epmPresent) { Debug.Assert( expectedPropertyTypeReference == null || expectedPropertyTypeReference.IsODataPrimitiveTypeKind() || expectedPropertyTypeReference.IsODataComplexTypeKind() || expectedPropertyTypeReference.IsNonEntityCollectionType(), "Only primitive, complex and collection types can be read by this method."); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.UseServerFormatBehavior || this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace), "Property elements must be in the OData namespace (unless we are running in WCF DS server format mode)."); this.XmlReader.AssertNotBuffering(); ODataProperty property = new ODataProperty(); string propertyName = this.XmlReader.LocalName; ValidationUtils.ValidatePropertyName(propertyName); ReaderValidationUtils.ValidateExpectedPropertyName(expectedPropertyName, propertyName); property.Name = propertyName; object propertyValue = this.ReadNonEntityValueImplementation( expectedPropertyTypeReference, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, epmPresent, propertyName); if (nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue && propertyValue == null) { property = null; } else { property.Value = propertyValue; } // Read past the end tag of the property or the start tag if the element is empty. this.XmlReader.Read(); this.XmlReader.AssertNotBuffering(); return(property); }
private void ReadPropertiesMetadataProperty(IODataJsonReaderEntryState entryState, ref ODataJsonReaderUtils.MetadataPropertyBitMask metadataPropertiesFoundBitField) { if (!base.ReadingResponse || (base.MessageReaderSettings.MaxProtocolVersion < ODataVersion.V3)) { base.JsonReader.SkipValue(); } else { ODataJsonReaderUtils.VerifyMetadataPropertyNotFound(ref metadataPropertiesFoundBitField, ODataJsonReaderUtils.MetadataPropertyBitMask.Properties, "properties"); if (base.JsonReader.NodeType != JsonNodeType.StartObject) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonEntryAndFeedDeserializer_PropertyInEntryMustHaveObjectValue("properties", base.JsonReader.NodeType)); } base.JsonReader.ReadStartObject(); while (base.JsonReader.NodeType == JsonNodeType.Property) { string associationLinkName = base.JsonReader.ReadPropertyName(); ValidationUtils.ValidateAssociationLinkName(associationLinkName); ReaderValidationUtils.ValidateNavigationPropertyDefined(associationLinkName, entryState.EntityType, base.MessageReaderSettings); base.JsonReader.ReadStartObject(); while (base.JsonReader.NodeType == JsonNodeType.Property) { if (string.CompareOrdinal(base.JsonReader.ReadPropertyName(), "associationuri") == 0) { string propertyValue = base.JsonReader.ReadStringValue("associationuri"); ODataJsonReaderUtils.ValidateMetadataStringProperty(propertyValue, "associationuri"); ODataAssociationLink associationLink = new ODataAssociationLink { Name = associationLinkName, Url = base.ProcessUriFromPayload(propertyValue) }; ValidationUtils.ValidateAssociationLink(associationLink); entryState.DuplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); ReaderUtils.AddAssociationLinkToEntry(entryState.Entry, associationLink); } else { base.JsonReader.SkipValue(); } } base.JsonReader.ReadEndObject(); } base.JsonReader.ReadEndObject(); } }
/// <summary> /// If an entity type name is found in the payload this method is called to apply it to the current scope. /// This method should be called even if the type name was not found in which case a null should be passed in. /// The method validates that some type will be available as the current entity type after it returns (if we are parsing using metadata). /// </summary> /// <param name="entityTypeNameFromPayload">The entity type name found in the payload or null if no type was specified in the payload.</param> protected void ApplyEntityTypeNameFromPayload(string entityTypeNameFromPayload) { Debug.Assert( this.scopes.Count > 0 && this.scopes.Peek().Item is ODataEntry, "Entity type can be applied only when in entry scope."); SerializationTypeNameAnnotation serializationTypeNameAnnotation; EdmTypeKind targetTypeKind; IEdmEntityTypeReference targetEntityTypeReference = (IEdmEntityTypeReference)ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind.Entity, /*defaultPrimitivePayloadType*/ null, this.CurrentEntityType.ToTypeReference(), entityTypeNameFromPayload, this.inputContext.Model, this.inputContext.MessageReaderSettings, this.inputContext.Version, () => EdmTypeKind.Entity, out targetTypeKind, out serializationTypeNameAnnotation); IEdmEntityType targetEntityType = null; ODataEntry entry = this.CurrentEntry; if (targetEntityTypeReference != null) { targetEntityType = targetEntityTypeReference.EntityDefinition(); entry.TypeName = targetEntityType.ODataFullName(); if (serializationTypeNameAnnotation != null) { entry.SetAnnotation(serializationTypeNameAnnotation); } } else if (entityTypeNameFromPayload != null) { entry.TypeName = entityTypeNameFromPayload; } // Set the current entity type since the type from payload might be more derived than // the expected one. this.CurrentEntityType = targetEntityType; }
/// <summary> /// Read an entity reference link. /// </summary> /// <returns>An instance of <see cref="ODataEntityReferenceLink"/> which was read.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the 'm:ref' element to read. /// Post-Condition: Any - the node after the 'm:ref' element which was read. /// </remarks> private ODataEntityReferenceLink ReadEntityReferenceId() { Debug.Assert(this.XmlReader != null, "this.XmlReader != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.NamespaceURI == this.XmlReader.ODataMetadataNamespace, "this.XmlReader.NamespaceURI == this.XmlReader.ODataMetadataNamespace"); Debug.Assert(this.XmlReader.LocalName == this.ODataRefElementName, "this.XmlReader.LocalName == this.ODataRefElementName"); ODataEntityReferenceLink link = new ODataEntityReferenceLink(); string uriString = this.XmlReader.GetAttribute(AtomConstants.AtomIdElementName); Debug.Assert(uriString != null, "In ATOM a entity reference id attribute on ref element can never represent a null value."); Uri xmlBaseUri = this.XmlReader.XmlBaseUri; Uri uri = this.ProcessUriFromPayload(uriString, xmlBaseUri); link.Url = uri; this.XmlReader.Skip(); ReaderValidationUtils.ValidateEntityReferenceLink(link); return(link); }
/// <summary> /// Reads the headers of a part. /// </summary> /// <param name="contentId">Content-ID read from changeset header, null if changeset part detected</param> /// <returns>true if the start of a changeset part was detected; otherwise false.</returns> internal bool ProcessPartHeader(out string contentId) { Debug.Assert(this.batchEncoding != null, "Batch encoding should have been established on first call to SkipToBoundary."); bool isChangeSetPart; ODataBatchOperationHeaders headers = this.ReadPartHeaders(out isChangeSetPart); contentId = null; if (isChangeSetPart) { // determine the changeset boundary and the changeset encoding from the content type header this.DetermineChangesetBoundaryAndEncoding(headers[ODataConstants.ContentTypeHeader]); if (this.changesetEncoding == null) { // NOTE: No changeset encoding was specified in the changeset's content type header. // Determine the changeset encoding from the first bytes in the changeset. // NOTE: We do not have to skip over the potential preamble of the encoding // because the batch reader will skip over everything (incl. the preamble) // until it finds the first changeset (or batch) boundary this.changesetEncoding = this.DetectEncoding(this.multipartMixedBatchInputContext.Stream); } // Verify that we only allow single byte encodings and UTF-8 for now. ReaderValidationUtils.ValidateEncodingSupportedInBatch(this.changesetEncoding); } else { // Read the contentId not only for request in changeset; but also // top-level request (if available), so that top-level request dependsOn // ids can be derived (even though top-level request ids are typically // not showing up on the wire). headers.TryGetValue(ODataConstants.ContentIdHeader, out contentId); } return(isChangeSetPart); }
/// <summary> /// Reads an annotation's value from the annotation value notation specified on the current element. /// </summary> /// <param name="expectedTypeReference">The expected type reference of the vocabulary term from the metadata.</param> /// <param name="attributeValueNotationTypeReference">The type reference indicated by the name of the attribute used in attribute value notation. /// For example, if the attribute was called "string", this will be a reference to the string type.</param> /// <param name="attributeValueNotationAttributeName">The name of the attribute used by attribute avalue notation.</param> /// <param name="attributeValueNotationAttributeValue">The value of the attribute used by attribute value notation.</param> /// <param name="typeAttributeValue">The value of the "m:type" attribute on the annotation element.</param> /// <param name="positionedOnEmptyElement">true if the annotation element is empty, false otherwise.</param> /// <param name="model">The edm model instance.</param> /// <param name="messageReaderSettings">The message reader settings instance.</param> /// <param name="version">The payload version to read.</param> /// <returns>The primitive value represented on this element via attribute value notation.</returns> private static ODataPrimitiveValue GetValueFromAttributeValueNotation( IEdmTypeReference expectedTypeReference, IEdmPrimitiveTypeReference attributeValueNotationTypeReference, string attributeValueNotationAttributeName, string attributeValueNotationAttributeValue, string typeAttributeValue, bool positionedOnEmptyElement, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version) { Debug.Assert(attributeValueNotationTypeReference != null, "attributeValueNotationTypeReference != null"); if (!positionedOnEmptyElement) { // If there is content in the body of the element, throw since it's ambiguous whether we should use the value from the attribute or the element content. throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedOnNonEmptyElement(attributeValueNotationAttributeName)); } // If both m:type is present and attribute value notation is being used, they must match. // For example, if m:type is "Edm.Int32", but the "string" attribute is also present, we should throw. if (typeAttributeValue != null && !string.Equals(attributeValueNotationTypeReference.Definition.ODataFullName(), typeAttributeValue, StringComparison.Ordinal)) { throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_AttributeValueNotationUsedWithIncompatibleType(typeAttributeValue, attributeValueNotationAttributeName)); } IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType( expectedTypeReference, EdmTypeKind.Primitive, attributeValueNotationTypeReference.Definition, attributeValueNotationTypeReference.ODataFullName(), attributeValueNotationTypeReference.Definition, model, messageReaderSettings, version); return(new ODataPrimitiveValue(AtomValueUtils.ConvertStringToPrimitive(attributeValueNotationAttributeValue, targetTypeReference.AsPrimitive()))); }
/// <summary> /// Read a set of top-level entity reference links. /// </summary> /// <param name="navigationProperty">The navigation property for which to read the entity reference links.</param> /// <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(IEdmNavigationProperty navigationProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); ODataEntityReferenceLinks entityReferenceLinks = new ODataEntityReferenceLinks(); if (this.JsonLightInputContext.ReadingResponse) { // Validate the metadata URI parsed from the payload against the expected navigation property. ReaderValidationUtils.ValidateEntityReferenceLinkMetadataUri(this.MetadataUriParseResult, navigationProperty); } this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/ true); // Read the start of the content array of the links this.JsonReader.ReadStartArray(); List <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>(); DuplicatePropertyNamesChecker linkDuplicatePropertyNamesChecker = this.JsonLightInputContext.CreateDuplicatePropertyNamesChecker(); while (this.JsonReader.NodeType != JsonNodeType.EndArray) { // read another link ODataEntityReferenceLink entityReferenceLink = this.ReadSingleEntityReferenceLink(linkDuplicatePropertyNamesChecker, /*topLevel*/ false); links.Add(entityReferenceLink); linkDuplicatePropertyNamesChecker.Clear(); } this.JsonReader.ReadEndArray(); this.ReadEntityReferenceLinksAnnotations(entityReferenceLinks, duplicatePropertyNamesChecker, /*forLinksStart*/ false); this.JsonReader.ReadEndObject(); entityReferenceLinks.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(links); return(entityReferenceLinks); }
/// <summary> /// Read an entity reference link. /// </summary> /// <returns>An instance of <see cref="ODataEntityReferenceLink"/> which was read.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the 'd:uri' element to read. /// Post-Condition: Any - the node after the 'd:uri' element which was read. /// </remarks> private ODataEntityReferenceLink ReadUriElement() { Debug.Assert(this.XmlReader != null, "this.XmlReader != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert( this.XmlReader.NamespaceURI == this.XmlReader.ODataNamespace || this.XmlReader.NamespaceURI == this.XmlReader.ODataMetadataNamespace, "this.XmlReader.NamespaceURI == this.XmlReader.ODataNamespace || this.XmlReader.NamespaceURI == this.XmlReader.ODataMetadataNamespace"); Debug.Assert(this.XmlReader.LocalName == this.ODataUriElementName, "this.XmlReader.LocalName == this.ODataUriElementName"); ODataEntityReferenceLink link = new ODataEntityReferenceLink(); // NOTE: get the base URI here before we read the content as string; reading the content as string will move the // reader to the end element and thus we lose the xml:base definition on the element. Uri xmlBaseUri = this.XmlReader.XmlBaseUri; string uriString = this.XmlReader.ReadElementValue(); Debug.Assert(uriString != null, "In ATOM a URI element can never represent a null value."); Uri uri = this.ProcessUriFromPayload(uriString, xmlBaseUri); link.Url = uri; ReaderValidationUtils.ValidateEntityReferenceLink(link); return(link); }
/// <summary> /// Reads the content of a properties in an element (complex value, m:properties, ...) /// </summary> /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param> /// <param name="properties">The list of properties to add properties to.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read properties from. /// Post-Condition: XmlNodeType.Element - The element to read properties from if it is an empty element. /// XmlNodeType.EndElement - The end element of the element to read properties from. /// </remarks> private void ReadPropertiesImplementation(IEdmStructuredType structuredType, List <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { Debug.Assert(properties != null, "properties != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertXmlCondition(XmlNodeType.Element); // Empty values are valid - they have no properties if (!this.XmlReader.IsEmptyElement) { // Read over the complex value element to its first child node (or end-element) this.XmlReader.ReadStartElement(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // Found a property IEdmProperty edmProperty = null; bool isOpen = false; bool ignoreProperty = false; if (structuredType != null) { // Lookup the property in metadata edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation) { throw new ODataException(o.Strings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType)); } // If the property was not declared, it must be open. isOpen = edmProperty == null; } if (ignoreProperty) { this.XmlReader.Skip(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); ODataProperty property = this.ReadProperty(edmProperty == null ? null : edmProperty.Type, nullValueReadBehaviorKind, epmPresent); Debug.Assert( property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue, "If we don't ignore null values the property must not be null."); if (property != null) { if (isOpen) { ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); properties.Add(property); } } } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the complex value. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } }