internal void WritePrimitiveValue(object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference) { IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType()); if (primitiveTypeReference == null) { throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName)); } string collectionItemTypeName = primitiveTypeReference.FullName(); if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(collectionItemTypeName, EdmTypeKind.Primitive); if (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, collectionItemTypeName) == 0) { collectionItemTypeName = null; } } if (expectedTypeReference != null) { ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference); } if ((collectionItemTypeName != null) && (collectionItemTypeName != "Edm.String")) { this.WritePropertyTypeAttribute(collectionItemTypeName); } AtomValueUtils.WritePrimitiveValue(base.XmlWriter, value); }
/// <summary> /// Writes an Xml element with the specified primitive value as content. /// </summary> /// <param name="writer">The Xml writer to write to.</param> /// <param name="prefix">The prefix for the element's namespace.</param> /// <param name="localName">The local name of the element.</param> /// <param name="ns">The namespace of the element.</param> /// <param name="textConstruct">The <see cref="AtomTextConstruct"/> value to be used as element content.</param> internal static void WriteTextConstruct(XmlWriter writer, string prefix, string localName, string ns, AtomTextConstruct textConstruct) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); Debug.Assert(prefix != null, "prefix != null"); Debug.Assert(!string.IsNullOrEmpty(localName), "!string.IsNullOrEmpty(localName)"); Debug.Assert(!string.IsNullOrEmpty(ns), "!string.IsNullOrEmpty(ns)"); writer.WriteStartElement(prefix, localName, ns); if (textConstruct != null) { AtomTextConstructKind textKind = textConstruct.Kind; writer.WriteAttributeString(AtomConstants.AtomTypeAttributeName, AtomValueUtils.ToString(textConstruct.Kind)); string textValue = textConstruct.Text ?? string.Empty; if (textKind == AtomTextConstructKind.Xhtml) { writer.WriteRaw(textValue); } else { writer.WriteString(textValue); } } writer.WriteEndElement(); }
private ODataEntityReferenceLinks ReadLinksElement() { ODataEntityReferenceLinks links = new ODataEntityReferenceLinks(); List <ODataEntityReferenceLink> sourceList = new List <ODataEntityReferenceLink>(); DuplicateEntityReferenceLinksElementBitMask none = DuplicateEntityReferenceLinksElementBitMask.None; if (base.XmlReader.IsEmptyElement) { goto Label_018C; } base.XmlReader.Read(); Label_002A: switch (base.XmlReader.NodeType) { case XmlNodeType.Element: if ((base.XmlReader.NamespaceEquals(base.XmlReader.ODataMetadataNamespace) && base.XmlReader.LocalNameEquals(this.ODataCountElementName)) && (base.Version >= ODataVersion.V2)) { VerifyEntityReferenceLinksElementNotFound(ref none, DuplicateEntityReferenceLinksElementBitMask.Count, base.XmlReader.ODataMetadataNamespace, "count"); long num = (long)AtomValueUtils.ReadPrimitiveValue(base.XmlReader, EdmCoreModel.Instance.GetInt64(false)); links.Count = new long?(num); base.XmlReader.Read(); goto Label_017A; } if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace)) { if (base.XmlReader.LocalNameEquals(this.ODataUriElementName)) { ODataEntityReferenceLink item = this.ReadUriElement(); sourceList.Add(item); goto Label_017A; } if (base.XmlReader.LocalNameEquals(this.ODataNextElementName) && (base.Version >= ODataVersion.V2)) { VerifyEntityReferenceLinksElementNotFound(ref none, DuplicateEntityReferenceLinksElementBitMask.NextLink, base.XmlReader.ODataNamespace, "next"); Uri xmlBaseUri = base.XmlReader.XmlBaseUri; string uriFromPayload = base.XmlReader.ReadElementValue(); links.NextPageLink = base.ProcessUriFromPayload(uriFromPayload, xmlBaseUri); goto Label_017A; } } break; case XmlNodeType.EndElement: goto Label_017A; } base.XmlReader.Skip(); Label_017A: if (base.XmlReader.NodeType != XmlNodeType.EndElement) { goto Label_002A; } Label_018C: base.XmlReader.Read(); links.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(sourceList); return(links); }
/// <summary> /// Given a property value returns the text value to be used in EPM. /// </summary> /// <param name="propertyValue">The value of the property.</param> /// <returns>The text representation of the value, or the method throws if the text representation was not possible to obtain.</returns> internal static string GetPropertyValueAsText(object propertyValue) { DebugUtils.CheckNoExternalCallers(); if (propertyValue == null) { return(null); } return(AtomValueUtils.ConvertPrimitiveToString(propertyValue)); }
/// <summary> /// Read an enumeration value from the reader. /// </summary> /// <param name="actualValueTypeReference">The thpe of the value to read.</param> /// <returns>An ODataEnumValue with the value read from the payload.</returns> private ODataEnumValue ReadEnumValue(IEdmEnumTypeReference actualValueTypeReference) { Debug.Assert(actualValueTypeReference != null, "actualValueTypeReference != null"); Debug.Assert(actualValueTypeReference.TypeKind() == EdmTypeKind.Enum, "Only Enum values can be read by this method."); this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); ODataEnumValue result = AtomValueUtils.ReadEnumValue(this.XmlReader, actualValueTypeReference); this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(result != null, "The method should never return null since it doesn't handle null values."); return(result); }
internal static string GetPropertyValueAsText(object propertyValue) { string str; if (propertyValue == null) { return(null); } if (!AtomValueUtils.TryConvertPrimitiveToString(propertyValue, out str)) { throw new ODataException(Microsoft.Data.OData.Strings.AtomValueUtils_CannotConvertValueToAtomPrimitive(propertyValue.GetType().FullName)); } return(str); }
/// <summary> /// Given a property value returns the text value to be used in EPM. /// </summary> /// <param name="propertyValue">The value of the property.</param> /// <returns>The text representation of the value, or the method throws if the text representation was not possible to obtain.</returns> internal static string GetPropertyValueAsText(object propertyValue) { DebugUtils.CheckNoExternalCallers(); if (propertyValue == null) { return(null); } string textPropertyValue; if (!AtomValueUtils.TryConvertPrimitiveToString(propertyValue, out textPropertyValue)) { throw new ODataException(Strings.AtomValueUtils_CannotConvertValueToAtomPrimitive(propertyValue.GetType().FullName)); } return(textPropertyValue); }
/// <summary> /// Writes a primitive value. /// </summary> /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param> /// <param name="value">The value to write.</param> /// <param name="expectedType">The expected resource type of the primitive value.</param> internal static void WritePrimitiveValue(XmlWriter writer, object value, ResourceType expectedType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(value != null, "value != null"); string typeName; if (!MetadataUtils.TryGetPrimitiveTypeName(value, out typeName)) { throw new ODataException(Strings.ODataWriter_UnsupportedPrimitiveType(value.GetType().FullName)); } if (typeName != EdmConstants.EdmStringTypeName) { WritePropertyTypeAttribute(writer, typeName); } AtomValueUtils.WritePrimitiveValue(writer, value, expectedType); }
/// <summary> /// Writes a primitive value. /// </summary> /// <param name="value">The value to write.</param> /// <param name="collectionValidator">The collection validator instance.</param> /// <param name="expectedTypeReference">The expected type of the primitive value.</param> internal void WritePrimitiveValue( object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(value != null, "value != null"); IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType()); if (primitiveTypeReference == null) { throw new ODataException(o.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName)); } string typeName = primitiveTypeReference.FullName(); if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Primitive); if (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0) { typeName = null; } } if (expectedTypeReference != null) { ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference); } if (typeName != null && typeName != Metadata.EdmConstants.EdmStringTypeName) { this.WritePropertyTypeAttribute(typeName); } AtomValueUtils.WritePrimitiveValue(this.XmlWriter, value); }
/// <summary> /// Writes the value of a primitive instance annotation. /// </summary> /// <param name="primitiveValue">The primitive value to write.</param> /// <param name="expectedTypeReference">The expected type of the annotation from the metadata.</param> private void WritePrimitiveInstanceAnnotationValue(ODataPrimitiveValue primitiveValue, IEdmTypeReference expectedTypeReference) { object clrValue = primitiveValue.Value; IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(clrValue.GetType()); string attributeValueNotationName = AtomInstanceAnnotation.LookupAttributeValueNotationNameByEdmTypeKind(primitiveTypeReference.PrimitiveKind()); // Some primitive values can be specified more concisely via an attribute rather than in the content of the xml element. This is called "attribute value notation". // If we're writing a type that supports this, then we always prefer attribute value notation over writing the value in the element content. if (attributeValueNotationName != null) { if (expectedTypeReference != null) { ValidationUtils.ValidateIsExpectedPrimitiveType(primitiveValue.Value, primitiveTypeReference, expectedTypeReference); } this.XmlWriter.WriteAttributeString(attributeValueNotationName, AtomValueUtils.ConvertPrimitiveToString(clrValue)); } else { this.WritePrimitiveValue(clrValue, /*collectionValidator*/ null, expectedTypeReference, primitiveValue.GetAnnotation <SerializationTypeNameAnnotation>()); } }
/// <summary> /// Writes an enumeration value. /// </summary> /// <param name="value">The value to write.</param> /// <param name="collectionValidator">The collection validator instance.</param> /// <param name="expectedTypeReference">The expected type of the enumeration value.</param> /// <param name="typeNameAnnotation">The optional type name annotation provided by the user on the OM for this enumeration value. The annotation value will override whatever type name is being written.</param> internal void WriteEnumValue( ODataEnumValue value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference, SerializationTypeNameAnnotation typeNameAnnotation) { Debug.Assert(value != null, "value != null"); // write type name without validation: string collectionItemTypeName; string typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(value, expectedTypeReference, typeNameAnnotation, collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); if (typeName != null) { Debug.Assert(typeName != EdmConstants.EdmStringTypeName, "Enum typeName != EdmConstants.StringTypeName"); this.WritePropertyTypeAttribute(typeName); } // write string value without validation: AtomValueUtils.WritePrimitiveValue(this.XmlWriter, value.Value); }
/// <summary> /// Writes a primitive value. /// </summary> /// <param name="value">The value to write.</param> /// <param name="collectionValidator">The collection validator instance.</param> /// <param name="expectedTypeReference">The expected type of the primitive value.</param> /// <param name="typeNameAnnotation">The optional type name annotation provided by the user on the OM for this primitive value. The annotation value will override whatever type name is being written.</param> internal void WritePrimitiveValue( object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference, SerializationTypeNameAnnotation typeNameAnnotation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(value != null, "value != null"); IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType()); if (primitiveTypeReference == null) { throw new ODataException(ODataErrorStrings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName)); } if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(primitiveTypeReference.FullName(), EdmTypeKind.Primitive); } if (expectedTypeReference != null) { ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference); } string collectionItemTypeName; string typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(value, primitiveTypeReference, typeNameAnnotation, collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); if (typeName != null && typeName != EdmConstants.EdmStringTypeName) { this.WritePropertyTypeAttribute(typeName); } AtomValueUtils.WritePrimitiveValue(this.XmlWriter, value); }
/// <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()))); }
internal void WriteTextConstruct(string prefix, string localName, string ns, AtomTextConstruct textConstruct) { base.XmlWriter.WriteStartElement(prefix, localName, ns); if (textConstruct != null) { AtomTextConstructKind kind = textConstruct.Kind; base.XmlWriter.WriteAttributeString("type", AtomValueUtils.ToString(textConstruct.Kind)); string text = textConstruct.Text; if (text == null) { text = string.Empty; } if (kind == AtomTextConstructKind.Xhtml) { ODataAtomWriterUtils.WriteRaw(base.XmlWriter, text); } else { ODataAtomWriterUtils.WriteString(base.XmlWriter, text); } } base.XmlWriter.WriteEndElement(); }
private void SetEpmValueForSegment(EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, List <ODataProperty> existingProperties, object propertyValue) { string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName; if (!epmInfo.Attribute.KeepInContent) { IEdmTypeReference type; ODataProperty property = existingProperties.FirstOrDefault <ODataProperty>(p => string.CompareOrdinal(p.Name, propertyName) == 0); ODataComplexValue value2 = null; if (property != null) { value2 = property.Value as ODataComplexValue; if (value2 == null) { return; } } IEdmProperty property2 = segmentStructuralTypeReference.FindProperty(propertyName); if ((property2 == null) && (propertyValuePathIndex != (epmInfo.PropertyValuePath.Length - 1))) { throw new ODataException(Microsoft.Data.OData.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath)); } if ((property2 == null) || (this.MessageReaderSettings.DisablePrimitiveTypeConversion && property2.Type.IsODataPrimitiveTypeKind())) { type = EdmCoreModel.Instance.GetString(true); } else { type = property2.Type; } switch (type.TypeKind()) { case EdmTypeKind.Primitive: object obj2; if (type.IsStream()) { throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty)); } if (propertyValue == null) { ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, type, this.atomInputContext.MessageReaderSettings, true, this.atomInputContext.Version); obj2 = null; } else { obj2 = AtomValueUtils.ConvertStringToPrimitive((string)propertyValue, type.AsPrimitive()); } this.AddEpmPropertyValue(existingProperties, propertyName, obj2, segmentStructuralTypeReference.IsODataEntityTypeKind()); return; case EdmTypeKind.Complex: { if (value2 == null) { value2 = new ODataComplexValue { TypeName = type.ODataFullName(), Properties = new ReadOnlyEnumerable <ODataProperty>() }; this.AddEpmPropertyValue(existingProperties, propertyName, value2, segmentStructuralTypeReference.IsODataEntityTypeKind()); } IEdmComplexTypeReference reference2 = type.AsComplex(); this.SetEpmValueForSegment(epmInfo, propertyValuePathIndex + 1, reference2, ReaderUtils.GetPropertiesList(value2.Properties), propertyValue); return; } case EdmTypeKind.Collection: { ODataCollectionValue value4 = new ODataCollectionValue { TypeName = type.ODataFullName(), Items = new ReadOnlyEnumerable((List <object>)propertyValue) }; this.AddEpmPropertyValue(existingProperties, propertyName, value4, segmentStructuralTypeReference.IsODataEntityTypeKind()); return; } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind)); } }
private object ReadPrimitiveValue(IEdmPrimitiveTypeReference actualValueTypeReference) { return(AtomValueUtils.ReadPrimitiveValue(base.XmlReader, actualValueTypeReference)); }
/// <summary> /// Writes an Xml element with the specified primitive value as content. /// </summary> /// <param name="prefix">The prefix for the element's namespace.</param> /// <param name="localName">The local name of the element.</param> /// <param name="ns">The namespace of the element.</param> /// <param name="textConstruct">The <see cref="AtomTextConstruct"/> value to be used as element content.</param> internal void WriteTextConstruct(string prefix, string localName, string ns, AtomTextConstruct textConstruct) { Debug.Assert(prefix != null, "prefix != null"); Debug.Assert(!string.IsNullOrEmpty(localName), "!string.IsNullOrEmpty(localName)"); Debug.Assert(!string.IsNullOrEmpty(ns), "!string.IsNullOrEmpty(ns)"); this.XmlWriter.WriteStartElement(prefix, localName, ns); if (textConstruct != null) { AtomTextConstructKind textKind = textConstruct.Kind; this.XmlWriter.WriteAttributeString(AtomConstants.AtomTypeAttributeName, AtomValueUtils.ToString(textConstruct.Kind)); string textValue = textConstruct.Text; if (textValue == null) { textValue = String.Empty; } if (textKind == AtomTextConstructKind.Xhtml) { ODataAtomWriterUtils.WriteRaw(this.XmlWriter, textValue); } else { ODataAtomWriterUtils.WriteString(this.XmlWriter, textValue); } } this.XmlWriter.WriteEndElement(); }
private void SetEpmValueForSegment( EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, List <ODataProperty> existingProperties, object propertyValue) { Debug.Assert(epmInfo != null, "epmInfo != null"); Debug.Assert(propertyValuePathIndex < epmInfo.PropertyValuePath.Length, "The propertyValuePathIndex is out of bounds."); Debug.Assert(existingProperties != null, "existingProperties != null"); string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName; // Do not set out-of-content values if the EPM is defined as KeepInContent=true. if (epmInfo.Attribute.KeepInContent) { return; } // Try to find the property in the existing properties // If the property value is atomic from point of view of EPM (non-streaming collection or primitive) then if it already exists // it must have been in-content, and thus we leave it as is (note that two EPMs can't map to the same property, we verify that upfront). // If the property value is non-atomic, then it is a complex value, we might want to merge the new value comming from EPM with it. ODataProperty existingProperty = existingProperties.FirstOrDefault(p => string.CompareOrdinal(p.Name, propertyName) == 0); ODataComplexValue existingComplexValue = null; if (existingProperty != null) { // In case the property exists and it's a complex value we will try to merge. // Note that if the property is supposed to be complex, but it already has a null value, then the null wins. // Since in-content null complex value wins over any EPM complex value. existingComplexValue = existingProperty.Value as ODataComplexValue; if (existingComplexValue == null) { return; } } IEdmProperty propertyMetadata = segmentStructuralTypeReference.FindProperty(propertyName); Debug.Assert(propertyMetadata != null || segmentStructuralTypeReference.IsOpen(), "We should have verified that if the property is not declared the type must be open."); if (propertyMetadata == null && propertyValuePathIndex != epmInfo.PropertyValuePath.Length - 1) { throw new ODataException(o.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath)); } // Open properties in EPM are by default of type Edm.String - there's no way to specify a typename in EPM // consumer is free to do the conversion later on if it needs to. // Note that this effectively means that ODataMessageReaderSettings.DisablePrimitiveTypeConversion is as if it's turned on for open EPM properties. IEdmTypeReference propertyType; if (propertyMetadata == null || (this.MessageReaderSettings.DisablePrimitiveTypeConversion && propertyMetadata.Type.IsODataPrimitiveTypeKind())) { propertyType = EdmCoreModel.Instance.GetString(/*nullable*/ true); } else { propertyType = propertyMetadata.Type; } // NOTE: WCF DS Server only applies the values when // - It's an open property // - It's not a key property // - It's a key property and it's a POST operation // ODataLib here will always set the property though. switch (propertyType.TypeKind()) { case EdmTypeKind.Primitive: { if (propertyType.IsStream()) { throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty)); } object primitiveValue; if (propertyValue == null) { ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, propertyType, this.atomInputContext.MessageReaderSettings, /*validateNullValue*/ true, this.atomInputContext.Version); primitiveValue = null; } else { // Convert the value to the desired target type primitiveValue = AtomValueUtils.ConvertStringToPrimitive((string)propertyValue, propertyType.AsPrimitive()); } this.AddEpmPropertyValue(existingProperties, propertyName, primitiveValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); } break; case EdmTypeKind.Complex: // Note: Unlike WCF DS we don't have a preexisting instance to override (since complex values are atomic, so we should not updated them) // In our case the complex value either doesn't exist yet on the entry being reported (easy, create it) // or it exists, but then it was created during reading of previous normal or EPM properties for this entry. It never exists before // we ever get to see the entity. So in our case we will never recreate the complex value, we always start with new one // and update it with new properties as they come. (Next time we will start over with a new complex value.) Debug.Assert( existingComplexValue == null || (existingProperty != null && existingProperty.Value == existingComplexValue), "If we have existing complex value, we must have an existing property as well."); Debug.Assert( epmInfo.PropertyValuePath.Length > propertyValuePathIndex + 1, "Complex value can not be a leaf segment in the source property path. We should have failed constructing the EPM trees for it."); if (existingComplexValue == null) { Debug.Assert(existingProperty == null, "If we don't have an existing complex value, then we must not have an existing property at all."); // Create a new complex value and set its type name to the type name of the property type (in case of EPM we never have type name from the payload) existingComplexValue = new ODataComplexValue { TypeName = propertyType.ODataFullName(), Properties = new ReadOnlyEnumerable <ODataProperty>() }; this.AddEpmPropertyValue(existingProperties, propertyName, existingComplexValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); } // Get the properties list of the complex value and recursively set the next EPM segment value to it. // Note that on inner complex value we don't need to check for duplicate properties // because EPM will never add a property which already exists (see the start of this method). IEdmComplexTypeReference complexPropertyTypeReference = propertyType.AsComplex(); Debug.Assert(complexPropertyTypeReference != null, "complexPropertyTypeReference != null"); this.SetEpmValueForSegment( epmInfo, propertyValuePathIndex + 1, complexPropertyTypeReference, ReaderUtils.GetPropertiesList(existingComplexValue.Properties), propertyValue); break; case EdmTypeKind.Collection: Debug.Assert(propertyType.IsNonEntityODataCollectionTypeKind(), "Collection types in EPM must be atomic."); // In this case the property value is the internal list of items. // Create a new collection value and set the list as the list of items on it. ODataCollectionValue collectionValue = new ODataCollectionValue { TypeName = propertyType.ODataFullName(), Items = new ReadOnlyEnumerable((List <object>)propertyValue) }; this.AddEpmPropertyValue(existingProperties, propertyName, collectionValue, segmentStructuralTypeReference.IsODataEntityTypeKind()); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind)); } }
/// <summary> /// Write the items in a MultiValue in ATOM format. /// </summary> /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param> /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param> /// <param name="multiValue">The MultiValue to write.</param> /// <param name="resourcePropertyType">The resource type of the multi value (or null if not metadata is available).</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="isWritingCollection">True if we are writing a collection instead of an entry.</param> /// <param name="version">The protocol version used for writing.</param> /// <param name="epmValueCache">Cache of values used in EPM so that we avoid multiple enumerations of properties/items. (can be null)</param> /// <param name="epmSourcePathSegment">The EPM source path segment which points to the multivalue property we're writing. (can be null)</param> private static void WriteMultiValue( XmlWriter writer, DataServiceMetadataProviderWrapper metadata, ODataMultiValue multiValue, ResourceType resourcePropertyType, bool isOpenPropertyType, bool isWritingCollection, ODataVersion version, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment) { Debug.Assert(multiValue != null, "multiValue != null"); string typeName = multiValue.TypeName; // resolve the type name to the resource type; if no type name is specified we will use the // type inferred from metadata MultiValueResourceType multiValueType = (MultiValueResourceType)MetadataUtils.ResolveTypeName(metadata, resourcePropertyType, ref typeName, ResourceTypeKind.MultiValue, isOpenPropertyType); if (typeName != null) { WritePropertyTypeAttribute(writer, typeName); } ResourceType expectedItemType = multiValueType == null ? null : multiValueType.ItemType; IEnumerable items = EpmValueCache.GetMultiValueItems(epmValueCache, epmSourcePathSegment, multiValue, true); if (items != null) { foreach (object itemValue in items) { object item; EpmMultiValueItemCache epmItemCache = itemValue as EpmMultiValueItemCache; if (epmItemCache != null) { item = epmItemCache.ItemValue; } else { item = itemValue; } ValidationUtils.ValidateMultiValueItem(item); writer.WriteStartElement(AtomConstants.ODataNamespacePrefix, AtomConstants.ODataMultiValueItemElementName, AtomConstants.ODataNamespace); ODataComplexValue complexValue = item as ODataComplexValue; if (complexValue != null) { WriteComplexValue(writer, metadata, complexValue, expectedItemType, false, isWritingCollection, version, epmItemCache, epmSourcePathSegment); } else { ODataMultiValue multiValueItem = item as ODataMultiValue; if (multiValueItem != null) { throw new ODataException(Strings.ODataWriter_NestedMultiValuesAreNotSupported); } else { AtomValueUtils.WritePrimitiveValue(writer, item, expectedItemType); } } writer.WriteEndElement(); } } }
/// <summary> /// Reads all top-level entity reference links and the (optional) inline count and next link elements. /// </summary> /// <returns>An <see cref="ODataEntityReferenceLinks"/> instance representing the read entity reference links.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The 'd:links' element. /// Post-Condtion: any - The node after the 'd:links' end element (or empty 'd:links' element). /// </remarks> private ODataEntityReferenceLinks ReadLinksElement() { 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.ODataNamespace"); Debug.Assert(this.XmlReader.LocalName == AtomConstants.ODataLinksElementName, "this.XmlReader.LocalName == AtomConstants.ODataLinksElementName"); ODataEntityReferenceLinks links = new ODataEntityReferenceLinks(); List <ODataEntityReferenceLink> linkList = new List <ODataEntityReferenceLink>(); DuplicateEntityReferenceLinksElementBitMask elementsReadBitmask = DuplicateEntityReferenceLinksElementBitMask.None; if (!this.XmlReader.IsEmptyElement) { // Move to the first child node of the element. this.XmlReader.Read(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.EndElement: // end of the <links> element continue; case XmlNodeType.Element: // <m:count> if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace) && this.XmlReader.LocalNameEquals(this.ODataCountElementName) && this.Version >= ODataVersion.V2) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.Count, this.XmlReader.ODataMetadataNamespace, AtomConstants.ODataCountElementName); // Note that we allow negative values to be read. long countValue = (long)AtomValueUtils.ReadPrimitiveValue(this.XmlReader, EdmCoreModel.Instance.GetInt64(false)); links.Count = countValue; // Read over the end element of the <m:count> element this.XmlReader.Read(); continue; } if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // <d:uri> if (this.XmlReader.LocalNameEquals(this.ODataUriElementName)) { ODataEntityReferenceLink link = this.ReadUriElement(); linkList.Add(link); continue; } // <d:next> if (this.XmlReader.LocalNameEquals(this.ODataNextElementName) && this.Version >= ODataVersion.V2) { VerifyEntityReferenceLinksElementNotFound( ref elementsReadBitmask, DuplicateEntityReferenceLinksElementBitMask.NextLink, this.XmlReader.ODataNamespace, AtomConstants.ODataNextLinkElementName); // 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(); links.NextPageLink = this.ProcessUriFromPayload(uriString, xmlBaseUri); continue; } } break; default: break; } this.XmlReader.Skip(); }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } // Read over the end element, or empty start element. this.XmlReader.Read(); links.Links = new ReadOnlyEnumerable <ODataEntityReferenceLink>(linkList); return(links); }